diff --git a/.gitignore b/.gitignore index bbc8386bda..5e54de49b2 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,8 @@ dist/ dist/ .tmp/ /.tmp/ +tmp/ + # Reports directory reports/ diff --git a/.release-it.json b/.release-it.json new file mode 100644 index 0000000000..2313cf40ab --- /dev/null +++ b/.release-it.json @@ -0,0 +1,47 @@ +{ + "non-interactive": false, + "dry-run": false, + "verbose": false, + "force": false, + "pkgFiles": ["package.json"], + "increment": "patch", + "buildCommand": false, + "safeBump": true, + "beforeChangelogCommand": false, + "requireCleanWorkingDir": true, + "requireUpstream": true, + "src": { + "commit": true, + "commitMessage": "chore(release): release %s", + "commitArgs": "", + "tag": true, + "tagName": "%s", + "tagAnnotation": "%s", + "push": true, + "pushArgs": "", + "pushRepo": null, + "beforeStartCommand": false, + "afterReleaseCommand": false + }, + "npm": { + "publish": false + }, + "github": { + "release": true, + "releaseName": "Release %s", + "draft": false, + "tokenRef": "GITHUB_TOKEN", + "assets": null, + "host": null + }, + "prompt": { + "src": { + "status": false, + "commit": true, + "tag": true, + "push": true, + "release": true, + "publish": true + } + } +} diff --git a/.travis.yml b/.travis.yml index d5ac196a57..7706c5cde4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,14 +1,18 @@ language: node_js node_js: - - "6" - "8" + - "6" + dist: trusty sudo: false # better for performance before_install: - export TZ=Europe/Brussels + # TODO remove this variable as it's probably not needed (defined by travis by default?): https://docs.travis-ci.com/user/environment-variables/ - TRAVIS=1 # used by build.sh - npm i -g npm@5.8.0 + # This ensures that we are authenticated without requiring to have an actual .npmrc file within the project + - 'echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > ~/.npmrc' install: # Create file & folder for Travis logs @@ -42,5 +46,9 @@ cache: script: - npm run lint:all - npm run test:ci:all + - npm run release:publish + # add publish-nightly + - ./scripts/ci/print-logs.sh + after_success: - npm run test:ci:coveralls:stark-core diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000000..e7e0eb3f74 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,29 @@ + +# 10.0.0-alpha.1 (2018-03-29) + + +### Bug Fixes + +* **build:** fixed issue with prettier config name with webpack plugin and added new scripts at root ([51be4f6](https://github.com/nationalbankbelgium/stark/commit/51be4f6)) +* **http:** fix unit tests. Enhance http demo in Starter ([#268](https://github.com/nationalbankbelgium/stark/issues/268)) ([6d609b8](https://github.com/nationalbankbelgium/stark/commit/6d609b8)), closes [#68](https://github.com/nationalbankbelgium/stark/issues/68) [#68](https://github.com/nationalbankbelgium/stark/issues/68) [#84](https://github.com/nationalbankbelgium/stark/issues/84) [#93](https://github.com/nationalbankbelgium/stark/issues/93) [angular/zone.js#1015](https://github.com/angular/zone.js/issues/1015) [#96](https://github.com/nationalbankbelgium/stark/issues/96) +* **lazy-loading:** Remove PreloadAllModules preloading strategy from routing coneiguration to make lazy-loaded modules to be actually lazy loaded :) ([9634dac](https://github.com/nationalbankbelgium/stark/commit/9634dac)) +* **lazy-loading:** Remove PreloadAllModules preloading strategy from routing coneiguration tz makz lazz-loaded modules to be actually lazy loaded :) ([80d09ce](https://github.com/nationalbankbelgium/stark/commit/80d09ce)) +* **linting:** clean stark-build/tslint.json. Remove obsolete options for 'ban' rule ([86ed26c](https://github.com/nationalbankbelgium/stark/commit/86ed26c)) +* **linting:** fix some TS linting issues ([8d5d6a8](https://github.com/nationalbankbelgium/stark/commit/8d5d6a8)) + + +### Features + +* **build:** added .gitattributes. Closes [#144](https://github.com/nationalbankbelgium/stark/issues/144). ([b4c3ef2](https://github.com/nationalbankbelgium/stark/commit/b4c3ef2)) +* **build:** added support for building a subset of the packages ([55ec4c1](https://github.com/nationalbankbelgium/stark/commit/55ec4c1)) +* **http:** create StarkHttp module. Fixed imports. Implemented small demo in Starter [[#96](https://github.com/nationalbankbelgium/stark/issues/96)] ([201edb8](https://github.com/nationalbankbelgium/stark/commit/201edb8)) +* **http:** implement Stark Http in stark-core (unit tests to be completed) [[#96](https://github.com/nationalbankbelgium/stark/issues/96)] ([579c59b](https://github.com/nationalbankbelgium/stark/commit/579c59b)) +* **http:** implement Stark Http in stark-core (unit tests to be completed) [[#96](https://github.com/nationalbankbelgium/stark/issues/96)] ([719d92d](https://github.com/nationalbankbelgium/stark/commit/719d92d)) +* **polyfills:** Update polyfills.browser.ts with the relevant polyfills needed only for IE11 and some special features from Angular. Add needed npm dependencies for those polyfils ([2b6a160](https://github.com/nationalbankbelgium/stark/commit/2b6a160)) +* **routing:** adapt CSP style-src directive to allow inline styles from UI Router visualizer ([8a1a8fa](https://github.com/nationalbankbelgium/stark/commit/8a1a8fa)) +* **routing:** add UI Router visualizer. Adapt CSP img-src directive to allow png images from UI Router visualizer ([3bc995b](https://github.com/nationalbankbelgium/stark/commit/3bc995b)) +* **routing:** replace Angular Router by UI Router ([24b70d4](https://github.com/nationalbankbelgium/stark/commit/24b70d4)) +* **stark-testing:** create separate stark-testing package and use it in all stark packages and starter ([#267](https://github.com/nationalbankbelgium/stark/issues/267)) ([204dc35](https://github.com/nationalbankbelgium/stark/commit/204dc35)), closes [#68](https://github.com/nationalbankbelgium/stark/issues/68) [#68](https://github.com/nationalbankbelgium/stark/issues/68) [#84](https://github.com/nationalbankbelgium/stark/issues/84) [#93](https://github.com/nationalbankbelgium/stark/issues/93) [angular/zone.js#1015](https://github.com/angular/zone.js/issues/1015) + + + diff --git a/README.md b/README.md index 0ff63f8d93..eba7cf4b06 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,9 @@ TODO add links to developer guide sections ### Contributing Please follow our [contribution guidelines](/CONTRIBUTING.md) +### Releaseing Stark +See [this page](/RELEASE.md) + ## Authors ### Sebastien Dubois diff --git a/RELEASE.md b/RELEASE.md new file mode 100644 index 0000000000..fada757ee3 --- /dev/null +++ b/RELEASE.md @@ -0,0 +1,44 @@ +# Releasing Stark + +## Pre-reqs +### Local +On your local machine, you must configure the `GITHUB_TOKEN` environment variable. +It will be used by release-it to push to and create the release page on GitHub (cfr release:prepare section below). + +### Travis +On Travis, the following should be configured: +* NPM_TOKEN environment variable + * if 2FA is enabled for the account the only auth-only level can be used: https://docs.npmjs.com/getting-started/using-two-factor-authentication#levels-of-authentication + * that variable MUST NEVER be logged/exposed. If exposed then the token MUST be revoked and the account password changed ASAP + +## Changelog +First of all: *Never* edit CHANGELOG.md manually! + +The changelog will be updated automatically as part of the release process and based on the commit log using conventional-changelog (https://github.com/conventional-changelog) +We use the Angular format for our changelog and for it to work properly, please make sure to respect our commit conventions (see CONTRIBUTING guide). + +## Creating a release +Make sure that: +* all changes have merged into master +* everything is up to date locally +* everything is clean locally +* execute `npm run release` + +Enjoy the show. + +## Publishing the release on npm +Once you have pushed the tag, Travis will handle things from there + +## What happens once a release is triggered + +### release +* first we make sure that there are no local changes (if there are we stop right there) +* then we execute release-it: https://github.com/webpro/release-it which + * bumps the version in the root package.json automatically (determines the bump type to use depending on the commit message logs) + * that version number will be used as basis in the build to adapt all other package.json files + * generates/updates the CHANGELOG.md file using: conventional-changelog: https://github.com/conventional-changelog + * commits both package.json and CHANGELOG.md + * creates a new git tag and pushes it + +### publish +TODO doc what happens during publish: https://github.com/NationalBankBelgium/stark/issues/54 diff --git a/build-functions.sh b/build-functions.sh index 35988789ce..5434d19f9e 100644 --- a/build-functions.sh +++ b/build-functions.sh @@ -1,53 +1,5 @@ #!/usr/bin/env bash -# Three-Fingered Claw technique :) -# Reference: https://stackoverflow.com/questions/1378274/in-a-bash-script-how-can-i-exit-the-entire-script-if-a-certain-condition-occurs -yell() { echo "$0: $*" >&2; } -die() { yell "$*"; exit 111; } -try() { "$@" || die "cannot $*"; } - -####################################### -# Echo the passed message if verbose mode is enabled -# Arguments: -# param1 - message to log if verbose mode is enabled -# param2 - depth: spaces to add before the string -####################################### -logDebug() { - if [[ ${VERBOSE} == true ]] || [[ ${TRACE} == true ]]; then - logInfo "$@" - fi -} - -####################################### -# Echo the passed message if trace mode is enabled -# Arguments: -# param1 - message to log if trace mode is enabled -# param2 - depth: spaces to add before the string -####################################### -logTrace() { - if [[ ${TRACE} == true ]]; then - logInfo "$@" - fi -} - -####################################### -# Echo the passed message -# Arguments: -# param1 - message to log if verbose mode is enabled -# param2 - (optional) depth: spaces to add before the string (defaults to 0) -####################################### -#log() { -# local message=${1:-NO MESSAGE TO LOG GIVEN TO log function (this is probably a mistake)} -# local numSpaces=${2:-0} -# printf "%${numSpaces}s$message\n" -#} -logInfo() { - local message="${1:-NO MESSAGE TO LOG GIVEN TO log function (this is probably a mistake)}" - local numSpaces="${2:-0}" - printf -v spacing '%*s' "$numSpaces" - printf "${spacing}%s\n" "$message" -} - ####################################### # Verifies a directory isn't in the ignored list # Arguments: diff --git a/build.sh b/build.sh index 47b649473a..a163862ec3 100644 --- a/build.sh +++ b/build.sh @@ -13,6 +13,7 @@ readonly currentDir=$(cd $(dirname $0); pwd) export NODE_PATH=${NODE_PATH:-}:${currentDir}/node_modules source ${currentDir}/scripts/ci/_travis-fold.sh +source ${currentDir}/util-functions.sh source ${currentDir}/build-functions.sh cd ${currentDir} @@ -27,12 +28,12 @@ TSC_PACKAGES=() # Packages that should not be compiled at all NODE_PACKAGES=(stark-build stark-testing) -ALL_PACKAGES=(stark-build stark-testing stark-core) +# We read from a file because the list is also shared with release-publish.sh +readarray -t ALL_PACKAGES < ./modules.txt BUILD_ALL=true BUNDLE=true VERSION_PREFIX=$(node -p "require('./package.json').version") -VERSION_SUFFIX="-$(git log --oneline -1 | awk '{print $1}')" # last commit id COMPILE_SOURCE=true TYPECHECK_ALL=true @@ -41,13 +42,6 @@ TRAVIS=${TRAVIS:-} VERBOSE=false TRACE=false -PROJECT_ROOT_DIR=`pwd` -logTrace "PROJECT_ROOT_DIR: ${PROJECT_ROOT_DIR}" 1 -ROOT_DIR=${PROJECT_ROOT_DIR}/packages -logTrace "ROOT_DIR: ${ROOT_DIR}" 1 -ROOT_OUT_DIR=${PROJECT_ROOT_DIR}/dist/packages -logTrace "ROOT_OUT_DIR: ${ROOT_OUT_DIR}" 1 - for ARG in "$@"; do case "$ARG" in --quick-bundle=*) @@ -60,7 +54,6 @@ for ARG in "$@"; do # parse to identify the packages to build PACKAGES_STR=${ARG#--packages=} - PACKAGES_STR=${ARG#--packages=} PACKAGES_STR="${PACKAGES_STR//,/ }" # replace , by ' ' PACKAGES_STR="${PACKAGES_STR//;/ }" # replace ; by ' ' PACKAGES_STR="${PACKAGES_STR// /_}" # replace all spaces by '_' @@ -113,9 +106,6 @@ for ARG in "$@"; do --bundle=*) BUNDLE=( "${ARG#--bundle=}" ) ;; - --publish) - VERSION_SUFFIX="" - ;; --compile=*) COMPILE_SOURCE=${ARG#--compile=} ;; @@ -139,6 +129,26 @@ for ARG in "$@"; do esac done +PROJECT_ROOT_DIR=`pwd` +logTrace "PROJECT_ROOT_DIR: ${PROJECT_ROOT_DIR}" 1 +ROOT_DIR=${PROJECT_ROOT_DIR}/packages +logTrace "ROOT_DIR: ${ROOT_DIR}" 1 +ROOT_OUT_DIR=${PROJECT_ROOT_DIR}/dist/packages +logTrace "ROOT_OUT_DIR: ${ROOT_OUT_DIR}" 1 + +# Making sure the variable exists +if [[ -z ${TRAVIS_TAG+x} ]]; then + TRAVIS_TAG="" +fi + +if [[ ${TRAVIS_TAG} == "" ]]; then + logTrace "Setting the version suffix to the latest commit hash" 1 + VERSION_SUFFIX="-$(git log --oneline -1 | awk '{print $1}')" # last commit id +else + logTrace "Build executed for a tag. Not using a version suffix!" 1 + VERSION_SUFFIX="" # last commit id +fi + VERSION="${VERSION_PREFIX}${VERSION_SUFFIX}" logInfo "=============================================" diff --git a/modules.txt b/modules.txt new file mode 100644 index 0000000000..ec07e407b0 --- /dev/null +++ b/modules.txt @@ -0,0 +1,3 @@ +stark-build +stark-testing +stark-core diff --git a/package.json b/package.json index 81937b6f72..4156d7dce6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "stark-srcs", - "version": "10.0.0-alpha.0", + "version": "10.0.0-alpha.1", "private": true, "description": "Stark - a framework for Angular apps", "author": "Stark Team ", @@ -26,6 +26,7 @@ "husky": "0.14.3", "lint-staged": "7.0.4", "prettier": "1.12.1", + "release-it": "7.2.1", "rollup": "0.58.1", "rollup-plugin-commonjs": "9.1.0", "rollup-plugin-node-resolve": "3.3.0", @@ -38,19 +39,11 @@ "uglify-es": "3.3.9" }, "scripts": { - "precommit": "lint-staged", - "prettier-check": "prettier **/*.{css,js,json,pcss,scss,ts} --write", - "stylelint-check": "stylelint-config-prettier-check", - "tsc": "tsc", - "ngc": "ngc", "build": "bash ./build.sh", "build:trace": "npm run build -- --trace", "build:stark-build": "npm run build -- --packages=stark-build", "build:stark-core": "npm run build -- --packages=stark-core", "build:stark-testing": "npm run build -- --packages=stark-testing", - "preupdate:starter": "npm run clean:starter", - "update:starter": "cd starter && npm install && cd ..", - "starter": "cd starter && npm start && cd ..", "clean": "rimraf ./dist", "clean:all": "npm run clean && npm run clean:stark-build && npm run clean:stark-core && npm run clean:stark-testing && npm run clean:starter", "clean:stark-build": "cd packages/stark-build && npm run clean && cd ../..", @@ -63,6 +56,9 @@ "clean:modules:stark-core": "cd packages/stark-core && npm run clean:modules && cd ../..", "clean:modules:stark-testing": "cd packages/stark-testing && npm run clean:modules dist && cd ../..", "clean:modules:starter": "cd starter && npm run clean:modules dist && cd ..", + "preupdate:starter": "npm run clean:starter", + "update:starter": "cd starter && npm install && cd ..", + "starter": "cd starter && npm start && cd ..", "lint": "tslint --config tslint.json --project ./tsconfig.json --format codeFrame", "lint:stark-core": "cd packages/stark-core && npm run lint && cd ../..", "lint:starter": "cd starter && npm run lint && cd ..", @@ -77,6 +73,12 @@ "install:ci:stark-testing": "cd packages/stark-testing && npm ci && cd ../..", "install:ci:starter": "cd starter && npm ci && cd ..", "install:travis:all": "npm run install:stark-build && npm run install:stark-testing && npm run install:stark-core && npm run build:trace && npm run update:starter", + "ngc": "ngc", + "precommit": "lint-staged", + "prettier-check": "prettier **/*.{css,js,json,pcss,scss,ts} --write", + "release": "release-it", + "release:publish": "bash ./release-publish.sh --trace", + "stylelint-check": "stylelint-config-prettier-check", "test:stark-core": "cd packages/stark-core && npm run test-fast && cd ../..", "test:starter": "cd starter && npm run test-fast && cd ../..", "test:all": "npm run test:stark-core && npm run test:starter", @@ -84,6 +86,7 @@ "test:ci:starter": "cd starter && npm run test-fast:ci && cd ../..", "test:ci:all": "npm run test:ci:stark-core && npm run test:ci:starter", "test:ci:coveralls:stark-core": "cd packages/stark-core && cat ./reports/coverage/packages/lcov.info | ../stark-testing/node_modules/coveralls/bin/coveralls.js", + "tsc": "tsc", "tslint": "tslint", "tslint-check": "tslint-config-prettier-check ./tslint.json" }, diff --git a/release-publish.sh b/release-publish.sh new file mode 100644 index 0000000000..08b7a91568 --- /dev/null +++ b/release-publish.sh @@ -0,0 +1,131 @@ +#!/usr/bin/env bash + +# TODO +#=================== +# provide a clean way to define/check the "current" version of node (i.e., the one we should execute the publish under/for) +# provide support for publishing only a subset of the packages (same --packages logic as in build.sh) +# provide support for publishing locally rather than from travis + +set -u -e -o pipefail + +VERBOSE=false +TRACE=false + +# We read from a file because the list is also shared with build.sh +readarray -t ALL_PACKAGES < ./modules.txt + +EXPECTED_REPO_SLUG="NationalBankBelgium/stark" + +# Uncomment below to test locally +#TRAVIS=yes +#TRAVIS_REPO_SLUG="dsebastien/stark" +#TRAVIS_TAG="ABC" + +readonly currentDir=$(cd $(dirname $0); pwd) + +source ${currentDir}/scripts/ci/_travis-fold.sh +source ${currentDir}/util-functions.sh + +cd ${currentDir} + +logInfo "=============================================" +logInfo "Stark Release" + +for ARG in "$@"; do + case "$ARG" in + --verbose) + logInfo "=============================================" + logInfo "Verbose mode enabled!" + VERBOSE=true + ;; + --trace) + logInfo "=============================================" + logInfo "Trace mode enabled!" + TRACE=true + ;; + *) + echo "Unknown option $ARG." + exit 1 + ;; + esac +done +logInfo "=============================================" + +PROJECT_ROOT_DIR=`pwd` +logTrace "PROJECT_ROOT_DIR: ${PROJECT_ROOT_DIR}" 1 +ROOT_PACKAGES_DIR=${PROJECT_ROOT_DIR}/dist/packages-dist +logTrace "ROOT_PACKAGES_DIR: ${ROOT_PACKAGES_DIR}" 1 + +travisFoldStart "publish checks" "no-xtrace" + +if [[ ${TRAVIS:-} ]]; then + logInfo "Releasing from Travis"; + logInfo "=============================================" + + # If the previous commands in the `script` section of .travis.yaml failed, then abort. + # The variable is not set in early stages of the build, so we default to 0 there. + # https://docs.travis-ci.com/user/environment-variables/ + if [[ ${TRAVIS_TEST_RESULT=0} == 1 ]]; then + exit 1; + fi + + # Don't even try if not running against the official repo + # We don't want release to run outside of our own little world + if [[ ${TRAVIS_REPO_SLUG} != ${EXPECTED_REPO_SLUG} ]]; then + logInfo "Skipping release because this is not the main repository."; + exit 0; + fi + + # Ensuring that this is the execution for Node x + # Without this check, we would publish a release for each node version we test under! :) + if [[ ${TRAVIS_NODE_VERSION} != "8" ]]; then + logInfo "Skipping release because this is not the expected version of node: ${TRAVIS_NODE_VERSION}" + exit 0; + fi + + logInfo "Verifying is this build has been triggered for a tag" + # Making sure the variable does exist.. + if [[ -z ${TRAVIS_TAG+x} ]]; then + TRAVIS_TAG="" + fi + + if [[ ${TRAVIS_TAG} == "" ]]; then + logTrace "Not publishing because this is not a build triggered for a tag" 1 + exit 0; + fi + + logInfo "Verifying that the NPM_TOKEN is available" + if [[ -z ${NPM_TOKEN+x} ]]; then + NPM_TOKEN="" + fi + + if [[ ${NPM_TOKEN} == "" ]]; then + logTrace "Not publishing because the NPM_TOKEN environment variable is is not defined correctly" 1 + exit 0; + fi +fi + +travisFoldEnd "publish checks" + +travisFoldStart "publish" "no-xtrace" +logInfo "Publishing all packages" +for PACKAGE in ${ALL_PACKAGES[@]} +do + travisFoldStart "publishing: ${PACKAGE}" "no-xtrace" + PACKAGE_FOLDER=${ROOT_PACKAGES_DIR}/${PACKAGE} + logTrace "Package path: ${PACKAGE_FOLDER}" 2 + cd ${PACKAGE_FOLDER} + TGZ_FILES=`find . -maxdepth 1 -type f | egrep -e ".tgz"`; + for file in ${TGZ_FILES}; do + logInfo "Publishing TGZ file: ${TGZ_FILES}" + npm publish ${file} --access public + logInfo "Package published!" + done + cd - > /dev/null; # go back to the previous folder without any output + travisFoldEnd "publishing: ${PACKAGE}" +done + +travisFoldEnd "publish" + +# Print return arrows as a log separator +travisFoldReturnArrows diff --git a/scripts/ci/print-logs.sh b/scripts/ci/print-logs.sh new file mode 100644 index 0000000000..2c14d45499 --- /dev/null +++ b/scripts/ci/print-logs.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +set -u -e -o pipefail + +# Setup environment +readonly thisDir=$(cd $(dirname $0); pwd) +source ${thisDir}/_travis-fold.sh + + +for FILE in ${LOGS_DIR}/*; do + travisFoldStart "print log file: ${FILE}" + cat $FILE + travisFoldEnd "print log file: ${FILE}" +done + +# Print return arrows as a log separator +travisFoldReturnArrows diff --git a/util-functions.sh b/util-functions.sh new file mode 100644 index 0000000000..04365c6492 --- /dev/null +++ b/util-functions.sh @@ -0,0 +1,49 @@ +#!/usr/bin/env bash + +# Three-Fingered Claw technique :) +# Reference: https://stackoverflow.com/questions/1378274/in-a-bash-script-how-can-i-exit-the-entire-script-if-a-certain-condition-occurs +yell() { echo "$0: $*" >&2; } +die() { yell "$*"; exit 111; } +try() { "$@" || die "cannot $*"; } + +####################################### +# Echo the passed message if verbose mode is enabled +# Arguments: +# param1 - message to log if verbose mode is enabled +# param2 - depth: spaces to add before the string +####################################### +logDebug() { + if [[ ${VERBOSE} == true ]] || [[ ${TRACE} == true ]]; then + logInfo "$@" + fi +} + +####################################### +# Echo the passed message if trace mode is enabled +# Arguments: +# param1 - message to log if trace mode is enabled +# param2 - depth: spaces to add before the string +####################################### +logTrace() { + if [[ ${TRACE} == true ]]; then + logInfo "$@" + fi +} + +####################################### +# Echo the passed message +# Arguments: +# param1 - message to log if verbose mode is enabled +# param2 - (optional) depth: spaces to add before the string (defaults to 0) +####################################### +#log() { +# local message=${1:-NO MESSAGE TO LOG GIVEN TO log function (this is probably a mistake)} +# local numSpaces=${2:-0} +# printf "%${numSpaces}s$message\n" +#} +logInfo() { + local message="${1:-NO MESSAGE TO LOG GIVEN TO log function (this is probably a mistake)}" + local numSpaces="${2:-0}" + printf -v spacing '%*s' "$numSpaces" + printf "${spacing}%s\n" "$message" +}