diff --git a/.github/linters/.hadolint.yml b/.github/linters/.hadolint.yml new file mode 100644 index 000000000..1a5ae337a --- /dev/null +++ b/.github/linters/.hadolint.yml @@ -0,0 +1,6 @@ +ignored: + - DL3048 + - DL3005 + - DL3008 + - DL3003 + - SC2035 diff --git a/.github/linters/.markdown-lint.yml b/.github/linters/.markdown-lint.yml new file mode 100644 index 000000000..e16596c0a --- /dev/null +++ b/.github/linters/.markdown-lint.yml @@ -0,0 +1,37 @@ +--- +default: true + +# Line length +# https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md013 +MD013: false + +# Inline HTML +# https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md033 +MD033: false + +# List indentation +# 2 spaces breaks list formatting in mkdocs +# https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md007 +MD007: + indent: 4 + +# Fenced code blocks should have a language specified +# We use a second, un-languaged code block to denote the output +# https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md040 +MD040: false + +# Blank line inside blockquote +# This is typically done when a section has a "New as of" or "Warning" in addition to a note +# May wish to take advantage of github-style admonitions +# https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md028 +MD028: false + +# No duplicate headers +# HISTORY.md has a ton of these +# https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md024 +MD024: false + +# First line h1 +# The issue template doesn't have one +# https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md041 +MD041: false diff --git a/.github/linters/.yamllint.yml b/.github/linters/.yamllint.yml new file mode 100644 index 000000000..fe6352dcc --- /dev/null +++ b/.github/linters/.yamllint.yml @@ -0,0 +1,8 @@ +--- +extends: default + +rules: + line-length: disable + +ignore: + - plugins/scheduler-k3s/templates/* diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 000000000..858d0cc6b --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,80 @@ +--- +name: "lint" + +# yamllint disable-line rule:truthy +on: + pull_request: + branches: + - "*" + push: + branches: + - "master" + +concurrency: + group: lint-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + hadolint: + name: hadolint + runs-on: ubuntu-22.04 + steps: + - name: Clone + uses: actions/checkout@v4 + - name: Run hadolint + uses: hadolint/hadolint-action@54c9adbab1582c2ef04b2016b760714a4bfde3cf + with: + config: .github/linters/.hadolint.yml + + markdown-lint: + name: markdown-lint + runs-on: ubuntu-22.04 + steps: + - name: Clone + uses: actions/checkout@v4 + - name: Setup node + uses: actions/setup-node@v4 + with: + node-version: "20" + cache: "npm" + cache-dependency-path: ".github/workflows/lint.yml" + - name: Install markdownlint-cli + run: npm install -g markdownlint-cli@0.35.0 + - name: Run markdown-lint + run: markdownlint -c .github/linters/.markdown-lint.yml *.md **/*.md + + shellcheck: + name: shellcheck + runs-on: ubuntu-22.04 + steps: + - name: Clone + uses: actions/checkout@v4 + - name: Run shellcheck + uses: ludeeus/action-shellcheck@00cae500b08a931fb5698e11e79bfbd38e612a38 + with: + ignore_paths: >- + ./tests/unit/fixtures/.profile.d/app.sh + + shfmt: + name: shfmt + runs-on: ubuntu-22.04 + steps: + - name: Clone + uses: actions/checkout@v4 + - name: Run shfmt + uses: luizm/action-sh-checker@c6edb3de93e904488b413636d96c6a56e3ad671a + env: + SHFMT_OPTS: -l -bn -ci -i 2 -d + with: + sh_checker_shellcheck_disable: true + + yamllint: + name: yamllint + runs-on: ubuntu-22.04 + steps: + - name: Clone + uses: actions/checkout@v4 + - name: Run yamllint + uses: ibiqlik/action-yamllint@2576378a8e339169678f9939646ee3ee325e845c + with: + config_file: ".github/linters/.yamllint.yml" diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f60747b8e..4d432b551 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -51,9 +51,6 @@ jobs: - name: shellcheck run: make shellcheck - - name: lint - run: make lint - - name: install requirements run: make deps fpm package_cloud diff --git a/.shellcheckrc b/.shellcheckrc new file mode 100644 index 000000000..e2d1334aa --- /dev/null +++ b/.shellcheckrc @@ -0,0 +1,7 @@ +disable=SC2128 +disable=SC1091 +disable=SC2002 +disable=SC2294 +disable=SC2034 +disable=SC2031 +disable=SC2030 diff --git a/CHANGELOG.md b/CHANGELOG.md index c73f453e5..f856fd6cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -877,7 +877,7 @@ All notable changes to this project will be documented in this file. - @michaelshobbs remove erlang from buildpack bundle -**NOTE: v0.4.0 is now based on heroku-16** +> NOTE: v0.4.0 is now based on heroku-16 ## [0.3.36](https://github.com/gliderlabs/herokuish/compare/v0.3.35...v0.3.36) - 2018-03-10 @@ -890,7 +890,7 @@ All notable changes to this project will be documented in this file. - @michaelshobbs Update nodejs to version v121 - @michaelshobbs Update go to version v85 -**NOTE: This will be the last version of herokuish based on cedar-14** +> NOTE: This will be the last version of herokuish based on cedar-14 ## [0.3.35](https://github.com/gliderlabs/herokuish/compare/v0.3.34...v0.3.35) - 2018-02-09 diff --git a/Dockerfile b/Dockerfile index 135430aca..3d161ec55 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,7 @@ ARG STACK_VERSION=20 FROM golang:1.22 AS builder RUN mkdir /src -ADD . /src/ +COPY . /src/ WORKDIR /src ARG VERSION @@ -15,7 +15,7 @@ ARG TARGETARCH ADD https://raw.githubusercontent.com/heroku/stack-images/main/heroku-${STACK_VERSION}/setup.sh /tmp/setup-01.sh ADD https://raw.githubusercontent.com/heroku/stack-images/main/heroku-${STACK_VERSION}-build/setup.sh /tmp/setup-02.sh -ADD bin/setup.sh /tmp/setup.sh +COPY bin/setup.sh /tmp/setup.sh RUN --mount=source=build-deps/${STACK_VERSION},target=/build STACK_VERSION=${STACK_VERSION} TARGETARCH=${TARGETARCH} /tmp/setup.sh && \ rm -rf /tmp/setup.sh @@ -24,9 +24,9 @@ ENV DEBIAN_FRONTEND noninteractive LABEL com.gliderlabs.herokuish/stack=$STACK RUN apt-get update -qq \ - && apt-get install -qq -y daemontools \ + && apt-get install --no-install-recommends -qq -y daemontools \ && cp /etc/ImageMagick-6/policy.xml /etc/ImageMagick-6/policy.xml.custom \ - && apt-get -y -o Dpkg::Options::=--force-confdef -o Dpkg::Options::=--force-confnew \ + && apt-get -y -o Dpkg::Options::=--force-confdef -o Dpkg::Options::=--force-confnew \ --allow-downgrades \ --allow-remove-essential \ --allow-change-held-packages \ diff --git a/Makefile b/Makefile index ebde00d18..dc76b33a5 100644 --- a/Makefile +++ b/Makefile @@ -159,18 +159,6 @@ ci-report: ruby -v rm -f ~/.gitconfig -lint: - # SC2002: Useless cat - https://github.com/koalaman/shellcheck/wiki/SC2002 - # SC2030: Modification of name is local - https://github.com/koalaman/shellcheck/wiki/SC2030 - # SC2031: Modification of name is local - https://github.com/koalaman/shellcheck/wiki/SC2031 - # SC2034: VAR appears unused - https://github.com/koalaman/shellcheck/wiki/SC2034 - # SC2206: Quote to prevent word splitting/globbing, or split robustly with mapfile or read -a. - # SC2001: See if you can use ${variable//search/replace} instead. - # SC2231: Quote expansions in this for loop glob to prevent wordsplitting, e.g. "$dir"/*.txt . - # SC2230: which is non-standard. Use builtin 'command -v' instead. - @echo linting... - shellcheck -e SC2002,SC2030,SC2031,SC2034,SC2206,SC2001,SC2231,SC2230 -s bash include/*.bash tests/**/tests.sh - release: build/rpm/$(NAME)-$(VERSION)-1.x86_64.rpm build/deb/$(NAME)_$(VERSION)_all.deb bin/gh-release bin/gh-release-body ls -lah build build/* || true chmod +x build/linux/$(NAME) build/darwin/$(NAME) diff --git a/README.md b/README.md index 1c607235d..f4e6b8e63 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ For example, build processes that produce Docker images without producing interm `herokuish exec` will by default drop root privileges through use of [setuidgid](https://cr.yp.to/daemontools/setuidgid.html), but if already running as a non-root user setuidgid will fail, you can opt-out from this by setting the env-var `HEROKUISH_SETUIDGUID=false`. -#### Buildpacks +### Buildpacks Herokuish does not come with any buildpacks, but it is tested against recent versions of Heroku supported buildpacks. You can see this information with `herokuish version`. Example output: @@ -78,7 +78,7 @@ buildpacks: You can install all supported buildpacks with `herokuish buildpack install`, or you can manually install buildpacks individually with `herokuish buildpack install [committish]`. You can also mount a directory containing your platform's supported buildpacks (see Paths, next section), or you could bake your supported buildpacks into an image. These are the types of decisions that are up to you. -#### Paths +### Paths Use `herokuish paths` to see relevant system paths it uses. You can use these to import or mount data for use inside a container. They can also be overridden by setting the appropriate environment variable. @@ -93,11 +93,11 @@ BUILDPACK_PATH=/tmp/buildpacks # Path to installed buildpacks ``` -#### Entrypoints +### Entrypoints Some subcommands are made to be used as default commands or entrypoint commands for containers. Specifically, herokuish detects if it was called as `/start`, `/exec`, or `/build` which will shortcut it to running those subcommands directly. This means you can either install the binary in those locations or create symlinks from those locations, allowing you to use them as your container entrypoint. -#### Help +### Help Don't be afraid of the help command. It actually tells you exactly what a command does: @@ -128,7 +128,7 @@ Having trouble pushing an app to Dokku or Heroku? Use Herokuish with a local Doc instance to debug. This is especially helpful with Dokku to help determine if it's a buildpack issue or an issue with Dokku. Buildpack issues should be filed against Herokuish. -#### Running an app against Herokuish +### Running an app against Herokuish ```shell docker run --rm -v /abs/app/path:/tmp/app gliderlabs/herokuish /bin/herokuish test @@ -147,7 +147,7 @@ Mounting your local app source directory to `/tmp/app` and running `/bin/herokui You can use this output when you submit issues. -#### Running an app tests using Heroku buildpacks +### Running an app tests using Heroku buildpacks ```shell docker run --rm -v /abs/app/path:/tmp/app gliderlabs/herokuish /bin/herokuish buildpack test @@ -175,7 +175,7 @@ docker run --platform linux/amd64 --rm -v /abs/app/path:/tmp/app gliderlabs/hero However, there is a risk of compatibility issues when running on a different platform than the one you are developing on. If you are getting strange compilation or segfaults, try running the build process on an x86 platform. -#### Troubleshooting +## Troubleshooting If you run into an issue and looking for more insight into what `herokuish` is doing, you can set the `$TRACE` environment variable. diff --git a/buildpacks/buildpack-clojure/tests/clojure-ring/test.sh b/buildpacks/buildpack-clojure/tests/clojure-ring/test.sh index e16c88e41..34b1ba1ed 100644 --- a/buildpacks/buildpack-clojure/tests/clojure-ring/test.sh +++ b/buildpacks/buildpack-clojure/tests/clojure-ring/test.sh @@ -1,3 +1,5 @@ -source "$(dirname $BASH_SOURCE)/../../../test" -app-test "$(basename $(dirname $BASH_SOURCE))" -buildpack-test "$(basename $(dirname $BASH_SOURCE))" +# shellcheck shell=bash + +source "$(dirname "$BASH_SOURCE")/../../../test" +app-test "$(basename "$(dirname "$BASH_SOURCE")")" +buildpack-test "$(basename "$(dirname "$BASH_SOURCE")")" diff --git a/buildpacks/buildpack-go/tests/go/test.sh b/buildpacks/buildpack-go/tests/go/test.sh index b6624e716..5287285c3 100644 --- a/buildpacks/buildpack-go/tests/go/test.sh +++ b/buildpacks/buildpack-go/tests/go/test.sh @@ -1,2 +1,4 @@ -source "$(dirname $BASH_SOURCE)/../../../test" -app-test "$(basename $(dirname $BASH_SOURCE))" +# shellcheck shell=bash + +source "$(dirname "$BASH_SOURCE")/../../../test" +app-test "$(basename "$(dirname "$BASH_SOURCE")")" diff --git a/buildpacks/buildpack-gradle/tests/gradle/test.sh b/buildpacks/buildpack-gradle/tests/gradle/test.sh index b6624e716..5287285c3 100644 --- a/buildpacks/buildpack-gradle/tests/gradle/test.sh +++ b/buildpacks/buildpack-gradle/tests/gradle/test.sh @@ -1,2 +1,4 @@ -source "$(dirname $BASH_SOURCE)/../../../test" -app-test "$(basename $(dirname $BASH_SOURCE))" +# shellcheck shell=bash + +source "$(dirname "$BASH_SOURCE")/../../../test" +app-test "$(basename "$(dirname "$BASH_SOURCE")")" diff --git a/buildpacks/buildpack-java/tests/java-jetty/test.sh b/buildpacks/buildpack-java/tests/java-jetty/test.sh index b6624e716..5287285c3 100644 --- a/buildpacks/buildpack-java/tests/java-jetty/test.sh +++ b/buildpacks/buildpack-java/tests/java-jetty/test.sh @@ -1,2 +1,4 @@ -source "$(dirname $BASH_SOURCE)/../../../test" -app-test "$(basename $(dirname $BASH_SOURCE))" +# shellcheck shell=bash + +source "$(dirname "$BASH_SOURCE")/../../../test" +app-test "$(basename "$(dirname "$BASH_SOURCE")")" diff --git a/buildpacks/buildpack-multi/tests/multi/test.sh b/buildpacks/buildpack-multi/tests/multi/test.sh index b6624e716..5287285c3 100644 --- a/buildpacks/buildpack-multi/tests/multi/test.sh +++ b/buildpacks/buildpack-multi/tests/multi/test.sh @@ -1,2 +1,4 @@ -source "$(dirname $BASH_SOURCE)/../../../test" -app-test "$(basename $(dirname $BASH_SOURCE))" +# shellcheck shell=bash + +source "$(dirname "$BASH_SOURCE")/../../../test" +app-test "$(basename "$(dirname "$BASH_SOURCE")")" diff --git a/buildpacks/buildpack-nodejs/tests/nodejs-express/test.sh b/buildpacks/buildpack-nodejs/tests/nodejs-express/test.sh index b6624e716..5287285c3 100644 --- a/buildpacks/buildpack-nodejs/tests/nodejs-express/test.sh +++ b/buildpacks/buildpack-nodejs/tests/nodejs-express/test.sh @@ -1,2 +1,4 @@ -source "$(dirname $BASH_SOURCE)/../../../test" -app-test "$(basename $(dirname $BASH_SOURCE))" +# shellcheck shell=bash + +source "$(dirname "$BASH_SOURCE")/../../../test" +app-test "$(basename "$(dirname "$BASH_SOURCE")")" diff --git a/buildpacks/buildpack-null/tests/null/test.sh b/buildpacks/buildpack-null/tests/null/test.sh index b6624e716..5287285c3 100644 --- a/buildpacks/buildpack-null/tests/null/test.sh +++ b/buildpacks/buildpack-null/tests/null/test.sh @@ -1,2 +1,4 @@ -source "$(dirname $BASH_SOURCE)/../../../test" -app-test "$(basename $(dirname $BASH_SOURCE))" +# shellcheck shell=bash + +source "$(dirname "$BASH_SOURCE")/../../../test" +app-test "$(basename "$(dirname "$BASH_SOURCE")")" diff --git a/buildpacks/buildpack-php/tests/php/README.md b/buildpacks/buildpack-php/tests/php/README.md index ffab40166..c924496f2 100644 --- a/buildpacks/buildpack-php/tests/php/README.md +++ b/buildpacks/buildpack-php/tests/php/README.md @@ -9,11 +9,11 @@ This application supports the [Getting Started with PHP on Heroku](https://devce Install the [Heroku Toolbelt](https://toolbelt.heroku.com/). ```sh -$ git clone git@github.com:heroku/php-getting-started.git # or clone your own fork -$ cd php-getting-started -$ heroku create -$ git push heroku main -$ heroku open +git clone git@github.com:heroku/php-getting-started.git # or clone your own fork +cd php-getting-started +heroku create +git push heroku main +heroku open ``` or diff --git a/buildpacks/buildpack-play/tests/play/test.sh b/buildpacks/buildpack-play/tests/play/test.sh index b6624e716..5287285c3 100644 --- a/buildpacks/buildpack-play/tests/play/test.sh +++ b/buildpacks/buildpack-play/tests/play/test.sh @@ -1,2 +1,4 @@ -source "$(dirname $BASH_SOURCE)/../../../test" -app-test "$(basename $(dirname $BASH_SOURCE))" +# shellcheck shell=bash + +source "$(dirname "$BASH_SOURCE")/../../../test" +app-test "$(basename "$(dirname "$BASH_SOURCE")")" diff --git a/buildpacks/buildpack-python/tests/python-django/test.sh b/buildpacks/buildpack-python/tests/python-django/test.sh index b6624e716..5287285c3 100644 --- a/buildpacks/buildpack-python/tests/python-django/test.sh +++ b/buildpacks/buildpack-python/tests/python-django/test.sh @@ -1,2 +1,4 @@ -source "$(dirname $BASH_SOURCE)/../../../test" -app-test "$(basename $(dirname $BASH_SOURCE))" +# shellcheck shell=bash + +source "$(dirname "$BASH_SOURCE")/../../../test" +app-test "$(basename "$(dirname "$BASH_SOURCE")")" diff --git a/buildpacks/buildpack-python/tests/python-flask/test.sh b/buildpacks/buildpack-python/tests/python-flask/test.sh index b6624e716..5287285c3 100644 --- a/buildpacks/buildpack-python/tests/python-flask/test.sh +++ b/buildpacks/buildpack-python/tests/python-flask/test.sh @@ -1,2 +1,4 @@ -source "$(dirname $BASH_SOURCE)/../../../test" -app-test "$(basename $(dirname $BASH_SOURCE))" +# shellcheck shell=bash + +source "$(dirname "$BASH_SOURCE")/../../../test" +app-test "$(basename "$(dirname "$BASH_SOURCE")")" diff --git a/buildpacks/buildpack-ruby/tests/ruby-sinatra/test.sh b/buildpacks/buildpack-ruby/tests/ruby-sinatra/test.sh index e16c88e41..34b1ba1ed 100644 --- a/buildpacks/buildpack-ruby/tests/ruby-sinatra/test.sh +++ b/buildpacks/buildpack-ruby/tests/ruby-sinatra/test.sh @@ -1,3 +1,5 @@ -source "$(dirname $BASH_SOURCE)/../../../test" -app-test "$(basename $(dirname $BASH_SOURCE))" -buildpack-test "$(basename $(dirname $BASH_SOURCE))" +# shellcheck shell=bash + +source "$(dirname "$BASH_SOURCE")/../../../test" +app-test "$(basename "$(dirname "$BASH_SOURCE")")" +buildpack-test "$(basename "$(dirname "$BASH_SOURCE")")" diff --git a/buildpacks/buildpack-scala/tests/scala/test.sh b/buildpacks/buildpack-scala/tests/scala/test.sh index b6624e716..5287285c3 100644 --- a/buildpacks/buildpack-scala/tests/scala/test.sh +++ b/buildpacks/buildpack-scala/tests/scala/test.sh @@ -1,2 +1,4 @@ -source "$(dirname $BASH_SOURCE)/../../../test" -app-test "$(basename $(dirname $BASH_SOURCE))" +# shellcheck shell=bash + +source "$(dirname "$BASH_SOURCE")/../../../test" +app-test "$(basename "$(dirname "$BASH_SOURCE")")" diff --git a/buildpacks/buildpack-static/tests/static/test.sh b/buildpacks/buildpack-static/tests/static/test.sh index b6624e716..5287285c3 100644 --- a/buildpacks/buildpack-static/tests/static/test.sh +++ b/buildpacks/buildpack-static/tests/static/test.sh @@ -1,2 +1,4 @@ -source "$(dirname $BASH_SOURCE)/../../../test" -app-test "$(basename $(dirname $BASH_SOURCE))" +# shellcheck shell=bash + +source "$(dirname "$BASH_SOURCE")/../../../test" +app-test "$(basename "$(dirname "$BASH_SOURCE")")" diff --git a/buildpacks/test b/buildpacks/test index e135e3268..b928c48d0 100755 --- a/buildpacks/test +++ b/buildpacks/test @@ -8,14 +8,13 @@ _run-cmd() { local buildpack="buildpack-${1%%-*}" cd "$(dirname "${BASH_SOURCE[0]}")" || return 1 local app_path="$PWD/$buildpack/tests/$app" - cd - &> /dev/null || return 1 - [[ "$CI" ]] || rmflag="--rm" + cd - &>/dev/null || return 1 + [[ "$CI" ]] || rmflag="--rm" [[ "$TRACE" ]] && debug_flag="-e TRACE=true" # shellcheck disable=SC2086 docker run $rmflag $debug_flag --env=USER=herokuishuser -v "$app_path:/tmp/app" herokuish:dev /bin/herokuish $cmd / "$app" } - # called by test.sh stub in app tests app-test() { declare app="$1" @@ -40,19 +39,19 @@ buildpack-test() { main() { case "$#" in - 0) # no args, run all the tests! - cd "$(dirname "${BASH_SOURCE[0]}")" || return 1 - basht "$PWD/buildpack*/tests/*/test.sh" - ;; - - 1) # one arg, expect name of buildpack to test - cd "$(dirname "${BASH_SOURCE[0]}")" || return 1 - basht "$PWD/$1/tests/*/test.sh" - ;; - - *) # more args, pass directly to basht - basht "$@" - ;; + 0) # no args, run all the tests! + cd "$(dirname "${BASH_SOURCE[0]}")" || return 1 + basht "$PWD/buildpack*/tests/*/test.sh" + ;; + + 1) # one arg, expect name of buildpack to test + cd "$(dirname "${BASH_SOURCE[0]}")" || return 1 + basht "$PWD/$1/tests/*/test.sh" + ;; + + *) # more args, pass directly to basht + basht "$@" + ;; esac } diff --git a/contrib/post-install b/contrib/post-install index 6a3fb6eae..0c9c0c4a6 100644 --- a/contrib/post-install +++ b/contrib/post-install @@ -1,6 +1,6 @@ #!/usr/bin/env bash -if which systemctl > /dev/null; then +if which systemctl >/dev/null; then echo "Starting docker" systemctl start docker sleep 5 @@ -14,7 +14,7 @@ docker images -a | grep "^gliderlabs\/herokuish" | grep -v latest | awk '{print echo 'Importing herokuish into docker (around 5 minutes)' if [[ -n "$http_proxy" ]] || [[ -n "$https_proxy" ]]; then - echo "See the docker pull docs for proxy configuration"; + echo "See the docker pull docs for proxy configuration" fi VERSION=$(cat /var/lib/herokuish/VERSION) diff --git a/include/buildpack.bash b/include/buildpack.bash index dd3cbb164..e6aad56e4 100644 --- a/include/buildpack.bash +++ b/include/buildpack.bash @@ -1,229 +1,233 @@ - _envfile-parse() { - declare desc="Parse input into shell export commands" - local key - local value - while read -r line || [[ -n "$line" ]]; do - [[ "$line" =~ ^#.* ]] && continue - [[ "$line" =~ ^$ ]] && continue - key=${line%%=*} - key=${key#*export } - value="${line#*=}" - case "$value" in - \'*|\"*) - value="${value}" - ;; - *) - value=\""${value}"\" - ;; - esac - echo "export ${key}=${value}" - done <<< "$(cat)" + declare desc="Parse input into shell export commands" + local key + local value + while read -r line || [[ -n "$line" ]]; do + [[ "$line" =~ ^#.* ]] && continue + [[ "$line" =~ ^$ ]] && continue + key=${line%%=*} + key=${key#*export } + value="${line#*=}" + case "$value" in + \'* | \"*) + # shellcheck disable=SC2269 + value="${value}" + ;; + *) + value=\""${value}"\" + ;; + esac + echo "export ${key}=${value}" + done <<<"$(cat)" } _move-build-to-app() { - shopt -s dotglob nullglob - # shellcheck disable=SC2086 - rm -rf ${app_path:?}/* - # build_path defined in outer scope - # shellcheck disable=SC2086,SC2154 - mv $build_path/* $app_path - shopt -u dotglob nullglob + shopt -s dotglob nullglob + # shellcheck disable=SC2086 + rm -rf ${app_path:?}/* + # build_path defined in outer scope + # shellcheck disable=SC2086,SC2154 + mv $build_path/* $app_path + shopt -u dotglob nullglob } _select-buildpack() { - if [[ -n "$BUILDPACK_URL" ]]; then - title "Fetching custom buildpack" - # buildpack_path defined in outer scope - # shellcheck disable=SC2154 - selected_path="$buildpack_path/custom" - rm -rf "$selected_path" - - IFS='#' read -r url commit <<< "$BUILDPACK_URL" - buildpack-install "$url" "$commit" custom &> /dev/null - # unprivileged_user & unprivileged_group defined in outer scope - # shellcheck disable=SC2154 - chown -R "$unprivileged_user:$unprivileged_group" "$buildpack_path/custom" - selected_name="$(unprivileged "$selected_path/bin/detect" "$build_path" || true)" - else - local buildpacks=($buildpack_path/*) - local valid_buildpacks=() - for buildpack in "${buildpacks[@]}"; do - unprivileged "$buildpack/bin/detect" "$build_path" &> /dev/null \ - && valid_buildpacks+=("$buildpack") - done - if [[ ${#valid_buildpacks[@]} -gt 1 ]]; then - title "Warning: Multiple default buildpacks reported the ability to handle this app. The first buildpack in the list below will be used." - echo "Detected buildpacks: $(sed -e "s:/tmp/buildpacks/[0-9][0-9]_buildpack-::g" <<< "${valid_buildpacks[@]}")" | indent - fi - if [[ ${#valid_buildpacks[@]} -gt 0 ]]; then - selected_path="${valid_buildpacks[0]}" - selected_name=$(unprivileged "$selected_path/bin/detect" "$build_path") - fi - fi - if [[ "$selected_path" ]] && [[ "$selected_name" ]]; then - title "$selected_name app detected" - else - title "Unable to select a buildpack" - exit 1 - fi + if [[ -n "$BUILDPACK_URL" ]]; then + title "Fetching custom buildpack" + # buildpack_path defined in outer scope + # shellcheck disable=SC2154 + selected_path="$buildpack_path/custom" + rm -rf "$selected_path" + + IFS='#' read -r url commit <<<"$BUILDPACK_URL" + buildpack-install "$url" "$commit" custom &>/dev/null + # unprivileged_user & unprivileged_group defined in outer scope + # shellcheck disable=SC2154 + chown -R "$unprivileged_user:$unprivileged_group" "$buildpack_path/custom" + selected_name="$(unprivileged "$selected_path/bin/detect" "$build_path" || true)" + else + # shellcheck disable=SC2206 + local buildpacks=($buildpack_path/*) + local valid_buildpacks=() + for buildpack in "${buildpacks[@]}"; do + unprivileged "$buildpack/bin/detect" "$build_path" &>/dev/null && valid_buildpacks+=("$buildpack") + done + if [[ ${#valid_buildpacks[@]} -gt 1 ]]; then + title "Warning: Multiple default buildpacks reported the ability to handle this app. The first buildpack in the list below will be used." + # shellcheck disable=SC2001 + echo "Detected buildpacks: $(sed -e "s:/tmp/buildpacks/[0-9][0-9]_buildpack-::g" <<<"${valid_buildpacks[@]}")" | indent + fi + if [[ ${#valid_buildpacks[@]} -gt 0 ]]; then + selected_path="${valid_buildpacks[0]}" + selected_name=$(unprivileged "$selected_path/bin/detect" "$build_path") + fi + fi + if [[ "$selected_path" ]] && [[ "$selected_name" ]]; then + title "$selected_name app detected" + else + title "Unable to select a buildpack" + exit 1 + fi } buildpack-build() { - declare desc="Build an application using installed buildpacks" - ensure-paths - [[ "$USER" ]] || randomize-unprivileged - buildpack-setup > /dev/null - buildpack-execute | indent - procfile-types | indent + declare desc="Build an application using installed buildpacks" + ensure-paths + [[ "$USER" ]] || randomize-unprivileged + buildpack-setup >/dev/null + buildpack-execute | indent + procfile-types | indent } buildpack-install() { - declare desc="Install buildpack from Git URL and optional committish" - declare url="$1" commit="$2" name="$3" - ensure-paths - if [[ ! "$url" ]]; then - asset-cat include/buildpacks.txt | while read -r name url commit; do - buildpack-install "$url" "$commit" "$name" - done - return - fi - # buildpack_path is defined in outer scope - # shellcheck disable=SC2154 - local target_path="$buildpack_path/${name:-$(basename "$url")}" - if [[ "$(git ls-remote "$url" &> /dev/null; echo $?)" -eq 0 ]]; then - if [[ "$commit" ]]; then - if ! git clone --branch "$commit" --quiet --depth 1 "$url" "$target_path" &>/dev/null; then - # if the shallow clone failed partway through, clean up and try a full clone - rm -rf "$target_path" - git clone "$url" "$target_path" - cd "$target_path" || return 1 - git checkout --quiet "$commit" - cd - > /dev/null || return 1 - else - echo "Cloning into '$target_path'..." - fi - else - git clone --depth=1 "$url" "$target_path" - fi - else - local tar_args - case "$url" in - *.tgz|*.tar.gz) - target_path="${target_path//.tgz}" - target_path="${target_path//.tar.gz}" - tar_args="-xzC" - ;; - *.tbz|*.tar.bz) - target_path="${target_path//.tbz}" - target_path="${target_path//.tar.bz}" - tar_args="-xjC" - ;; - *.tar) - target_path="${target_path//.tar}" - tar_args="-xC" - ;; - esac - echo "Downloading '$url' into '$target_path'..." - mkdir -p "$target_path" - curl -s --retry 2 "$url" | tar "$tar_args" "$target_path" - chown -R root:root "$target_path" - chmod 755 "$target_path" - fi - - find "$buildpack_path" \( \! -user "${unprivileged_user:-32767}" -o \! -group "${unprivileged_group:-32767}" \) -print0 | xargs -P 0 -0 --no-run-if-empty chown --no-dereference "${unprivileged_user:-32767}:${unprivileged_group:-32767}" + declare desc="Install buildpack from Git URL and optional committish" + declare url="$1" commit="$2" name="$3" + ensure-paths + if [[ ! "$url" ]]; then + asset-cat include/buildpacks.txt | while read -r name url commit; do + buildpack-install "$url" "$commit" "$name" + done + return + fi + # buildpack_path is defined in outer scope + # shellcheck disable=SC2154 + local target_path="$buildpack_path/${name:-$(basename "$url")}" + if [[ "$( + git ls-remote "$url" &>/dev/null + echo $? + )" -eq 0 ]]; then + if [[ "$commit" ]]; then + if ! git clone --branch "$commit" --quiet --depth 1 "$url" "$target_path" &>/dev/null; then + # if the shallow clone failed partway through, clean up and try a full clone + rm -rf "$target_path" + git clone "$url" "$target_path" + cd "$target_path" || return 1 + git checkout --quiet "$commit" + cd - >/dev/null || return 1 + else + echo "Cloning into '$target_path'..." + fi + else + git clone --depth=1 "$url" "$target_path" + fi + else + local tar_args + case "$url" in + *.tgz | *.tar.gz) + target_path="${target_path//.tgz/}" + target_path="${target_path//.tar.gz/}" + tar_args="-xzC" + ;; + *.tbz | *.tar.bz) + target_path="${target_path//.tbz/}" + target_path="${target_path//.tar.bz/}" + tar_args="-xjC" + ;; + *.tar) + target_path="${target_path//.tar/}" + tar_args="-xC" + ;; + esac + echo "Downloading '$url' into '$target_path'..." + mkdir -p "$target_path" + curl -s --retry 2 "$url" | tar "$tar_args" "$target_path" + chown -R root:root "$target_path" + chmod 755 "$target_path" + fi + + find "$buildpack_path" \( \! -user "${unprivileged_user:-32767}" -o \! -group "${unprivileged_group:-32767}" \) -print0 | xargs -P 0 -0 --no-run-if-empty chown --no-dereference "${unprivileged_user:-32767}:${unprivileged_group:-32767}" } buildpack-list() { - declare desc="List installed buildpacks" - ensure-paths - ls -1 "$buildpack_path" + declare desc="List installed buildpacks" + ensure-paths + ls -1 "$buildpack_path" } buildpack-setup() { - # Buildpack expectations - # app_path defined in outer scope - # shellcheck disable=SC2154 - export APP_DIR="$app_path" - # shellcheck disable=SC2154 - export HOME="$app_path" - export REQUEST_ID="build-$RANDOM" - export STACK="${STACK:-heroku-20}" - # build_path defined in outer scope - # shellcheck disable=SC2154 - cp -r "$app_path/." "$build_path" - - # Prepare dropped privileges - # unprivileged_user defined in outer scope - # shellcheck disable=SC2154 - usermod --home "$HOME" "$unprivileged_user" > /dev/null 2>&1 - - # Prepare permissions quicker for slower filesystems - # vars defined in outer scope - # shellcheck disable=SC2154 - find "$app_path" \( \! -user "$unprivileged_user" -o \! -group "$unprivileged_group" \) -print0 | xargs -P 0 -0 --no-run-if-empty chown --no-dereference "$unprivileged_user:$unprivileged_group" - # shellcheck disable=SC2154 - find "$build_path" \( \! -user "$unprivileged_user" -o \! -group "$unprivileged_group" \) -print0 | xargs -P 0 -0 --no-run-if-empty chown --no-dereference "$unprivileged_user:$unprivileged_group" - # shellcheck disable=SC2154 - find "$cache_path" \( \! -user "$unprivileged_user" -o \! -group "$unprivileged_group" \) -print0 | xargs -P 0 -0 --no-run-if-empty chown --no-dereference "$unprivileged_user:$unprivileged_group" - # shellcheck disable=SC2154 - find "$env_path" \( \! -user "$unprivileged_user" -o \! -group "$unprivileged_group" \) -print0 | xargs -P 0 -0 --no-run-if-empty chown --no-dereference "$unprivileged_user:$unprivileged_group" - # shellcheck disable=SC2154 - find "$buildpack_path" \( \! -user "$unprivileged_user" -o \! -group "$unprivileged_group" \) -print0 | xargs -P 0 -0 --no-run-if-empty chown --no-dereference "$unprivileged_user:$unprivileged_group" - - # Useful settings / features - export CURL_CONNECT_TIMEOUT="30" - export CURL_TIMEOUT="180" - - # Buildstep backwards compatibility - if [[ -f "$app_path/.env" ]]; then - # shellcheck disable=SC2046 - eval $(cat "$app_path/.env" | _envfile-parse) - fi + # Buildpack expectations + # app_path defined in outer scope + # shellcheck disable=SC2154 + export APP_DIR="$app_path" + # shellcheck disable=SC2154 + export HOME="$app_path" + export REQUEST_ID="build-$RANDOM" + export STACK="${STACK:-heroku-20}" + # build_path defined in outer scope + # shellcheck disable=SC2154 + cp -r "$app_path/." "$build_path" + + # Prepare dropped privileges + # unprivileged_user defined in outer scope + # shellcheck disable=SC2154 + usermod --home "$HOME" "$unprivileged_user" >/dev/null 2>&1 + + # Prepare permissions quicker for slower filesystems + # vars defined in outer scope + # shellcheck disable=SC2154 + find "$app_path" \( \! -user "$unprivileged_user" -o \! -group "$unprivileged_group" \) -print0 | xargs -P 0 -0 --no-run-if-empty chown --no-dereference "$unprivileged_user:$unprivileged_group" + # shellcheck disable=SC2154 + find "$build_path" \( \! -user "$unprivileged_user" -o \! -group "$unprivileged_group" \) -print0 | xargs -P 0 -0 --no-run-if-empty chown --no-dereference "$unprivileged_user:$unprivileged_group" + # shellcheck disable=SC2154 + find "$cache_path" \( \! -user "$unprivileged_user" -o \! -group "$unprivileged_group" \) -print0 | xargs -P 0 -0 --no-run-if-empty chown --no-dereference "$unprivileged_user:$unprivileged_group" + # shellcheck disable=SC2154 + find "$env_path" \( \! -user "$unprivileged_user" -o \! -group "$unprivileged_group" \) -print0 | xargs -P 0 -0 --no-run-if-empty chown --no-dereference "$unprivileged_user:$unprivileged_group" + # shellcheck disable=SC2154 + find "$buildpack_path" \( \! -user "$unprivileged_user" -o \! -group "$unprivileged_group" \) -print0 | xargs -P 0 -0 --no-run-if-empty chown --no-dereference "$unprivileged_user:$unprivileged_group" + + # Useful settings / features + export CURL_CONNECT_TIMEOUT="30" + export CURL_TIMEOUT="180" + + # Buildstep backwards compatibility + if [[ -f "$app_path/.env" ]]; then + # shellcheck disable=SC2046 + eval $(cat "$app_path/.env" | _envfile-parse) + fi } buildpack-execute() { - _select-buildpack - cd "$build_path" || return 1 - unprivileged "$selected_path/bin/compile" "$build_path" "$cache_path" "$env_path" - if [[ -f "$selected_path/bin/release" ]]; then - unprivileged "$selected_path/bin/release" "$build_path" "$cache_path" > "$build_path/.release" - fi - if [[ -f "$build_path/.release" ]]; then - config_vars="$(cat "$build_path/.release" | yaml-get config_vars)" - if [[ "$config_vars" ]]; then - mkdir -p "$build_path/.profile.d" - OIFS=$IFS - IFS=$'\n' - for var in $config_vars; do - echo "export $(echo "$var" | sed -e 's/=/="/' -e 's/$/"/')" >> "$build_path/.profile.d/00_config_vars.sh" - done - IFS=$OIFS - fi - fi - cd - > /dev/null || return 1 - _move-build-to-app + _select-buildpack + cd "$build_path" || return 1 + unprivileged "$selected_path/bin/compile" "$build_path" "$cache_path" "$env_path" + if [[ -f "$selected_path/bin/release" ]]; then + unprivileged "$selected_path/bin/release" "$build_path" "$cache_path" >"$build_path/.release" + fi + if [[ -f "$build_path/.release" ]]; then + config_vars="$(cat "$build_path/.release" | yaml-get config_vars)" + if [[ "$config_vars" ]]; then + mkdir -p "$build_path/.profile.d" + OIFS=$IFS + IFS=$'\n' + for var in $config_vars; do + echo "export $(echo "$var" | sed -e 's/=/="/' -e 's/$/"/')" >>"$build_path/.profile.d/00_config_vars.sh" + done + IFS=$OIFS + fi + fi + cd - >/dev/null || return 1 + _move-build-to-app } buildpack-test() { - declare desc="Build and run tests for an application using installed buildpacks" - ensure-paths - [[ "$USER" ]] || randomize-unprivileged - buildpack-setup > /dev/null - _select-buildpack - - if [[ ! -f "$selected_path/bin/test-compile" ]] || [[ ! -f "$selected_path/bin/test" ]]; then - echo "Selected buildpack does not support test feature" - exit 1 - fi - - cd "$build_path" || return 1 - chmod 755 "$selected_path/bin/test-compile" - unprivileged "$selected_path/bin/test-compile" "$build_path" "$cache_path" "$env_path" - - cd "$app_path" || return 1 - _move-build-to-app - procfile-load-profile - chmod 755 "$selected_path/bin/test" - unprivileged "$selected_path/bin/test" "$app_path" "$env_path" + declare desc="Build and run tests for an application using installed buildpacks" + ensure-paths + [[ "$USER" ]] || randomize-unprivileged + buildpack-setup >/dev/null + _select-buildpack + + if [[ ! -f "$selected_path/bin/test-compile" ]] || [[ ! -f "$selected_path/bin/test" ]]; then + echo "Selected buildpack does not support test feature" + exit 1 + fi + + cd "$build_path" || return 1 + chmod 755 "$selected_path/bin/test-compile" + unprivileged "$selected_path/bin/test-compile" "$build_path" "$cache_path" "$env_path" + + cd "$app_path" || return 1 + _move-build-to-app + procfile-load-profile + chmod 755 "$selected_path/bin/test" + unprivileged "$selected_path/bin/test" "$app_path" "$env_path" } diff --git a/include/cmd.bash b/include/cmd.bash index 8be6696b5..4439abe33 100644 --- a/include/cmd.bash +++ b/include/cmd.bash @@ -1,81 +1,84 @@ - declare -A CMDS cmd-list() { - declare desc="Lists available commands" - declare ns="$1" - cmd-list-keys "$ns" | sed "s/$ns://" + declare desc="Lists available commands" + declare ns="$1" + cmd-list-keys "$ns" | sed "s/$ns://" } cmd-list-keys() { - declare ns="$1" - for k in "${!CMDS[@]}"; do - echo "$k" - done | grep "^$ns:" | sort + declare ns="$1" + for k in "${!CMDS[@]}"; do + echo "$k" + done | grep "^$ns:" | sort } cmd-list-ns() { - for k in "${!CMDS[@]}"; do - echo "$k" - done | grep -v : | sort + for k in "${!CMDS[@]}"; do + echo "$k" + done | grep -v : | sort } cmd-export() { - declare desc="Exports a function as a command" - declare fn="$1" as="${2:-$1}" - local ns="" - for n in $(cmd-list-ns); do - echo "$fn" | grep "^$n-" &> /dev/null && ns="$n" - done - CMDS["$ns:${as/#$ns-/}"]="$fn" + declare desc="Exports a function as a command" + declare fn="$1" as="${2:-$1}" + local ns="" + for n in $(cmd-list-ns); do + echo "$fn" | grep "^$n-" &>/dev/null && ns="$n" + done + CMDS["$ns:${as/#$ns-/}"]="$fn" } cmd-export-ns() { - declare ns="$1" desc="$2" - eval "$1() { + declare ns="$1" desc="$2" + eval "$1() { declare desc=\"$desc\" cmd-ns $1 \"\$@\"; }" - cmd-export "$1" - CMDS["$1"]="$1" + cmd-export "$1" + CMDS["$1"]="$1" } cmd-ns() { - local ns="$1"; shift - local cmd="$1"; shift || true - local status=0 - if cmd-list "$ns" | grep ^"$cmd"\$ &> /dev/null; then - ${CMDS["$ns:$cmd"]} "$@" - else - if [[ "$cmd" ]]; then - echo "No such command: $cmd" - status=2 - elif [[ "$ns" ]]; then - fn-desc "$ns" - fi - echo - echo "Available commands:" - for cmd in $(cmd-list "$ns"); do - printf " %-24s %s\n" "$cmd" "$(fn-desc "${CMDS["$ns:$cmd"]}")" - for subcmd in $(cmd-list "$cmd"); do - printf " %-24s %s\n" "$subcmd" "$(fn-desc "${CMDS["$cmd:$subcmd"]}")" - done - done - echo - exit $status - fi + local ns="$1" + shift + local cmd="$1" + shift || true + local status=0 + if cmd-list "$ns" | grep ^"$cmd"\$ &>/dev/null; then + ${CMDS["$ns:$cmd"]} "$@" + else + if [[ "$cmd" ]]; then + echo "No such command: $cmd" + status=2 + elif [[ "$ns" ]]; then + fn-desc "$ns" + fi + echo + echo "Available commands:" + for cmd in $(cmd-list "$ns"); do + printf " %-24s %s\n" "$cmd" "$(fn-desc "${CMDS["$ns:$cmd"]}")" + for subcmd in $(cmd-list "$cmd"); do + printf " %-24s %s\n" "$subcmd" "$(fn-desc "${CMDS["$cmd:$subcmd"]}")" + done + done + echo + exit $status + fi } cmd-help() { - declare desc="Shows help information for a command" - declare args="$*" - if [[ "$args" ]]; then - for cmd; do true; done # last arg - local ns="${args/%$cmd/}"; ns="${ns/% /}"; ns="${ns/ /-}" - local fn="${CMDS["$ns:$cmd"]}" - fn-info "$fn" 1 - else - cmd-ns "" - fi + declare desc="Shows help information for a command" + declare args="$*" + if [[ "$args" ]]; then + for cmd; do true; done # last arg + local ns="${args/%$cmd/}" + ns="${ns/% /}" + ns="${ns/ /-}" + local fn="${CMDS["$ns:$cmd"]}" + fn-info "$fn" 1 + else + cmd-ns "" + fi } cmd-export cmd-help help diff --git a/include/default_user.bash b/include/default_user.bash index 6f7b7ae3f..0d4acf268 100644 --- a/include/default_user.bash +++ b/include/default_user.bash @@ -1,7 +1,7 @@ #!/usr/bin/env bash -addgroup --quiet --gid "32767" "herokuishuser" && \ -adduser \ +addgroup --quiet --gid "32767" "herokuishuser" \ + && adduser \ --shell /bin/bash \ --disabled-password \ --force-badname \ diff --git a/include/fn.bash b/include/fn.bash index d5231ef2b..3a6fa9eb1 100644 --- a/include/fn.bash +++ b/include/fn.bash @@ -1,25 +1,25 @@ - fn-args() { - declare desc="Inspect a function's arguments" - local argline - argline=$(type "$1" | grep declare | grep -v "declare desc" | head -1) - echo -e "${argline// /"\n"}" | awk -F= '/=/{print "<"$1">"}' | tr "\n" " " + declare desc="Inspect a function's arguments" + local argline + argline=$(type "$1" | grep declare | grep -v "declare desc" | head -1) + echo -e "${argline// /"\n"}" | awk -F= '/=/{print "<"$1">"}' | tr "\n" " " } fn-desc() { - declare desc="Inspect a function's description" - desc="" - eval "$(type "$1" | grep desc | head -1)"; echo $desc + declare desc="Inspect a function's description" + desc="" + eval "$(type "$1" | grep desc | head -1)" + echo "$desc" } fn-info() { - declare desc="Inspects a function" - declare fn="$1" showsource="$2" - echo "$fn $(fn-args "$fn")" - echo " $(fn-desc "$fn")" - echo - if [[ "$showsource" ]]; then - type "$fn" | tail -n +2 - echo - fi + declare desc="Inspects a function" + declare fn="$1" showsource="$2" + echo "$fn $(fn-args "$fn")" + echo " $(fn-desc "$fn")" + echo + if [[ "$showsource" ]]; then + type "$fn" | tail -n +2 + echo + fi } diff --git a/include/herokuish.bash b/include/herokuish.bash index 234e2e559..bccb358fa 100644 --- a/include/herokuish.bash +++ b/include/herokuish.bash @@ -1,8 +1,7 @@ - if [[ "${BASH_VERSINFO[0]}" -lt "4" ]]; then - echo "!! Your system Bash is out of date: $BASH_VERSION" - echo "!! Please upgrade to Bash 4 or greater." - exit 2 + echo "!! Your system Bash is out of date: $BASH_VERSION" + echo "!! Please upgrade to Bash 4 or greater." + exit 2 fi readonly app_path="${APP_PATH:-/app}" @@ -18,139 +17,140 @@ declare unprivileged_group="${USER/nobody/nogroup}" export PS1='\[\033[01;34m\]\w\[\033[00m\] \[\033[01;32m\]$ \[\033[00m\]' ensure-paths() { - mkdir -p \ - "$app_path" \ - "$env_path" \ - "$build_path" \ - "$cache_path" \ - "$buildpack_path" + mkdir -p \ + "$app_path" \ + "$env_path" \ + "$build_path" \ + "$cache_path" \ + "$buildpack_path" } paths() { - declare desc="Shows path settings" - printf "%-32s # %s\n" \ - "APP_PATH=$app_path" "Application path during runtime" \ - "ENV_PATH=$env_path" "Path to files for defining base environment" \ - "BUILD_PATH=$build_path" "Working directory during builds" \ - "CACHE_PATH=$cache_path" "Buildpack cache location" \ - "IMPORT_PATH=$import_path" "Mounted path to copy to app path" \ - "BUILDPACK_PATH=$buildpack_path" "Path to installed buildpacks" + declare desc="Shows path settings" + printf "%-32s # %s\n" \ + "APP_PATH=$app_path" "Application path during runtime" \ + "ENV_PATH=$env_path" "Path to files for defining base environment" \ + "BUILD_PATH=$build_path" "Working directory during builds" \ + "CACHE_PATH=$cache_path" "Buildpack cache location" \ + "IMPORT_PATH=$import_path" "Mounted path to copy to app path" \ + "BUILDPACK_PATH=$buildpack_path" "Path to installed buildpacks" } version() { - declare desc="Show version and supported version info" - echo "herokuish: ${HEROKUISH_VERSION:-dev}" - echo "buildpacks:" - asset-cat include/buildpacks.txt | sed -e 's/.*heroku\///' -e 's/.*dokku\///' | xargs printf " %-26s %s\n" + declare desc="Show version and supported version info" + echo "herokuish: ${HEROKUISH_VERSION:-dev}" + echo "buildpacks:" + asset-cat include/buildpacks.txt | sed -e 's/.*heroku\///' -e 's/.*dokku\///' | xargs printf " %-26s %s\n" } title() { - echo $'\e[1G----->' "$@" + echo $'\e[1G----->' "$@" } indent() { - while read -r line; do - if [[ "$line" == --* ]] || [[ "$line" == ==* ]]; then - # shellcheck disable=SC2086 - echo $'\e[1G'$line - else - echo $'\e[1G ' "$line" - fi - done + while read -r line; do + if [[ "$line" == --* ]] || [[ "$line" == ==* ]]; then + # shellcheck disable=SC2086 + echo $'\e[1G'$line + else + echo $'\e[1G ' "$line" + fi + done } unprivileged() { - setuidgid "$unprivileged_user" "$@" + setuidgid "$unprivileged_user" "$@" } detect-unprivileged() { - unprivileged_user="$(stat -c %U "$app_path")" - unprivileged_group="${unprivileged_user/nobody/nogroup}" + unprivileged_user="$(stat -c %U "$app_path")" + unprivileged_group="${unprivileged_user/nobody/nogroup}" } randomize-unprivileged() { - local userid="$((RANDOM+1000))" - local username="u${userid}" - - addgroup --quiet --gid "$userid" "$username" - adduser \ - --shell /bin/bash \ - --disabled-password \ - --force-badname \ - --no-create-home \ - --uid "$userid" \ - --gid "$userid" \ - --gecos '' \ - --quiet \ - --home "$app_path" \ - "$username" - - unprivileged_user="$username" - unprivileged_group="$username" + local userid="$((RANDOM + 1000))" + local username="u${userid}" + + addgroup --quiet --gid "$userid" "$username" + adduser \ + --shell /bin/bash \ + --disabled-password \ + --force-badname \ + --no-create-home \ + --uid "$userid" \ + --gid "$userid" \ + --gecos '' \ + --quiet \ + --home "$app_path" \ + "$username" + + unprivileged_user="$username" + unprivileged_group="$username" } herokuish-test() { - declare desc="Test running an app through Herokuish" - declare path="${1:-/}" expected="$2" - export PORT=5678 - echo "::: BUILDING APP :::" - buildpack-build - echo "::: STARTING WEB :::" - procfile-start web & - for retry in $(seq 1 30); do - sleep 1 - if ! nc -z -w 5 localhost "$PORT"; then - echo "::: RETRYING LISTENER ($retry) :::" - else - echo "::: FOUND LISTENER :::" && break - fi - done - echo "::: CHECKING APP :::" - local output - output="$(curl --fail --retry 10 --retry-delay 2 -v -s "localhost:${PORT}${path}")" - if [[ "$expected" ]]; then - sleep 1 - echo "::: APP OUTPUT :::" - echo -e "$output" - if [[ "$output" != "$expected" ]]; then - echo "::: TEST FAILED :::" - exit 2 - fi - fi - echo "::: TEST FINISHED :::" + declare desc="Test running an app through Herokuish" + declare path="${1:-/}" expected="$2" + export PORT=5678 + echo "::: BUILDING APP :::" + buildpack-build + echo "::: STARTING WEB :::" + procfile-start web & + for retry in $(seq 1 30); do + sleep 1 + if ! nc -z -w 5 localhost "$PORT"; then + echo "::: RETRYING LISTENER ($retry) :::" + else + echo "::: FOUND LISTENER :::" && break + fi + done + echo "::: CHECKING APP :::" + local output + output="$(curl --fail --retry 10 --retry-delay 2 -v -s "localhost:${PORT}${path}")" + if [[ "$expected" ]]; then + sleep 1 + echo "::: APP OUTPUT :::" + echo -e "$output" + if [[ "$output" != "$expected" ]]; then + echo "::: TEST FAILED :::" + exit 2 + fi + fi + echo "::: TEST FINISHED :::" } main() { - set -eo pipefail; [[ "$TRACE" ]] && set -x - - if [[ -d "$import_path" ]] && [[ -n "$(ls -A "$import_path")" ]]; then - rm -rf "$app_path" && cp -r "$import_path" "$app_path" - fi - - cmd-export paths - cmd-export version - cmd-export herokuish-test test - - cmd-export-ns buildpack "Use and install buildpacks" - cmd-export buildpack-build - cmd-export buildpack-install - cmd-export buildpack-list - cmd-export buildpack-test - - cmd-export-ns slug "Manage application slugs" - cmd-export slug-import - cmd-export slug-generate - cmd-export slug-export - - cmd-export-ns procfile "Use Procfiles and run app commands" - cmd-export procfile-start - cmd-export procfile-exec - cmd-export procfile-parse - - case "$SELF" in - /start) procfile-start "$@";; - /exec) procfile-exec "$@";; - /build) buildpack-build;; - *) cmd-ns "" "$@"; - esac + set -eo pipefail + [[ "$TRACE" ]] && set -x + + if [[ -d "$import_path" ]] && [[ -n "$(ls -A "$import_path")" ]]; then + rm -rf "$app_path" && cp -r "$import_path" "$app_path" + fi + + cmd-export paths + cmd-export version + cmd-export herokuish-test test + + cmd-export-ns buildpack "Use and install buildpacks" + cmd-export buildpack-build + cmd-export buildpack-install + cmd-export buildpack-list + cmd-export buildpack-test + + cmd-export-ns slug "Manage application slugs" + cmd-export slug-import + cmd-export slug-generate + cmd-export slug-export + + cmd-export-ns procfile "Use Procfiles and run app commands" + cmd-export procfile-start + cmd-export procfile-exec + cmd-export procfile-parse + + case "$SELF" in + /start) procfile-start "$@" ;; + /exec) procfile-exec "$@" ;; + /build) buildpack-build ;; + *) cmd-ns "" "$@" ;; + esac } diff --git a/include/procfile.bash b/include/procfile.bash index 431a77389..e306ce467 100644 --- a/include/procfile.bash +++ b/include/procfile.bash @@ -1,127 +1,125 @@ - yaml-esque-keys() { - declare desc="Get process type keys from colon-separated structure" - while read -r line || [[ -n "$line" ]]; do - [[ "$line" =~ ^#.* ]] && continue - [[ "$line" == *:* ]] || continue - key=${line%%:*} - echo "$key" - done <<< "$(cat)" + declare desc="Get process type keys from colon-separated structure" + while read -r line || [[ -n "$line" ]]; do + [[ "$line" =~ ^#.* ]] && continue + [[ "$line" == *:* ]] || continue + key=${line%%:*} + echo "$key" + done <<<"$(cat)" } yaml-esque-get() { - declare desc="Get key value from colon-separated structure" - declare key="$1" - local inputkey cmd - while read -r line || [[ -n "$line" ]]; do - [[ "$line" =~ ^#.* ]] && continue - inputkey=${line%%:*} - cmd=${line#*:} - if [[ "$inputkey" == "$key" ]]; then - echo "$cmd" - break - fi - done <<< "$(cat)" + declare desc="Get key value from colon-separated structure" + declare key="$1" + local inputkey cmd + while read -r line || [[ -n "$line" ]]; do + [[ "$line" =~ ^#.* ]] && continue + inputkey=${line%%:*} + cmd=${line#*:} + if [[ "$inputkey" == "$key" ]]; then + echo "$cmd" + break + fi + done <<<"$(cat)" } procfile-parse() { - declare desc="Get command string for a process type from Procfile" - declare type="$1" - # app_path is defined in outer scope - # shellcheck disable=SC2154 - cat "$app_path/Procfile" | yaml-esque-get "$type" + declare desc="Get command string for a process type from Procfile" + declare type="$1" + # app_path is defined in outer scope + # shellcheck disable=SC2154 + cat "$app_path/Procfile" | yaml-esque-get "$type" } procfile-start() { - declare desc="Run process type command from Procfile through exec" - declare type="$1" - local processcmd - processcmd="$(procfile-parse "$type")" - if [[ -z "$processcmd" ]]; then - echo "Proc entrypoint ${type} does not exist. Please check your Procfile" - exit 1 - else - procfile-exec "$processcmd" - fi + declare desc="Run process type command from Procfile through exec" + declare type="$1" + local processcmd + processcmd="$(procfile-parse "$type")" + if [[ -z "$processcmd" ]]; then + echo "Proc entrypoint ${type} does not exist. Please check your Procfile" + exit 1 + else + procfile-exec "$processcmd" + fi } procfile-exec() { - declare desc="Run as unprivileged user with Heroku-like env" - [[ "$USER" ]] || detect-unprivileged - procfile-setup-home - cd "$app_path" || return 1 - procfile-load-env - procfile-load-profile - # unprivileged_user is defined in outer scope - # shellcheck disable=SC2154,SC2046 - if [[ "$HEROKUISH_SETUIDGUID" == "false" ]]; then - exec $(eval echo "$@") - else - exec setuidgid "$unprivileged_user" $(eval echo "$@") - fi + declare desc="Run as unprivileged user with Heroku-like env" + [[ "$USER" ]] || detect-unprivileged + procfile-setup-home + cd "$app_path" || return 1 + procfile-load-env + procfile-load-profile + # unprivileged_user is defined in outer scope + # shellcheck disable=SC2154,SC2046 + if [[ "$HEROKUISH_SETUIDGUID" == "false" ]]; then + exec $(eval echo "$@") + else + exec setuidgid "$unprivileged_user" $(eval echo "$@") + fi } procfile-types() { - title "Discovering process types" - if [[ -f "$app_path/Procfile" ]]; then - local types - types="$(cat "$app_path/Procfile" | yaml-esque-keys | sort | uniq | xargs echo)" - echo "Procfile declares types -> ${types// /, }" - return - fi - if [[ -s "$app_path/.release" ]]; then - local default_types - default_types="$(cat "$app_path/.release" | yaml-keys default_process_types | xargs echo)" - # selected_name is defined in outer scope - # shellcheck disable=SC2154 - [[ "$default_types" ]] && \ - echo "Default types for $selected_name -> ${default_types// /, }" - for type in $default_types; do - echo "$type: $(cat "$app_path/.release" | yaml-get default_process_types "$type")" >> "$app_path/Procfile" - done - return - fi - echo "No process types found" + title "Discovering process types" + if [[ -f "$app_path/Procfile" ]]; then + local types + types="$(cat "$app_path/Procfile" | yaml-esque-keys | sort | uniq | xargs echo)" + echo "Procfile declares types -> ${types// /, }" + return + fi + if [[ -s "$app_path/.release" ]]; then + local default_types + default_types="$(cat "$app_path/.release" | yaml-keys default_process_types | xargs echo)" + # selected_name is defined in outer scope + # shellcheck disable=SC2154 + [[ "$default_types" ]] && echo "Default types for $selected_name -> ${default_types// /, }" + for type in $default_types; do + echo "$type: $(cat "$app_path/.release" | yaml-get default_process_types "$type")" >>"$app_path/Procfile" + done + return + fi + echo "No process types found" } procfile-load-env() { - local varname - # env_path is defined in outer scope - # shellcheck disable=SC2154 - if [[ -d "$env_path" ]]; then - shopt -s nullglob - for e in $env_path/*; do - varname=$(basename "$e") - export "$varname=$(cat "$e")" - done - fi + local varname + # env_path is defined in outer scope + # shellcheck disable=SC2154 + if [[ -d "$env_path" ]]; then + shopt -s nullglob + for e in "$env_path"/*; do + varname=$(basename "$e") + export "$varname=$(cat "$e")" + done + fi } procfile-load-profile() { - shopt -s nullglob - for file in /etc/profile.d/*.sh; do - # shellcheck disable=SC1090 - source "$file" - done - mkdir -p "$app_path/.profile.d" - for file in $app_path/.profile.d/*.sh; do - # shellcheck disable=SC1090 - source "$file" - done - if [[ -s "$app_path/.profile" ]]; then - # shellcheck disable=SC1090 - source "$app_path/.profile" - fi - shopt -u nullglob - hash -r + shopt -s nullglob + for file in /etc/profile.d/*.sh; do + # shellcheck disable=SC1090 + source "$file" + done + mkdir -p "$app_path/.profile.d" + for file in "$app_path/.profile.d"/*.sh; do + # shellcheck disable=SC1090 + source "$file" + done + if [[ -s "$app_path/.profile" ]]; then + # shellcheck disable=SC1090 + source "$app_path/.profile" + fi + shopt -u nullglob + hash -r } procfile-setup-home() { - export HOME="$app_path" - usermod --home "$app_path" "$unprivileged_user" >/dev/null 2>&1 - if [[ "$HEROKUISH_DISABLE_CHOWN" == "true" ]]; then - # unprivileged_user & unprivileged_group are defined in outer scope - # shellcheck disable=SC2154 - find "$app_path" \( \! -user "$unprivileged_user" -o \! -group "$unprivileged_group" \) -print0 | xargs -0 -r chown "$unprivileged_user:$unprivileged_group" - fi + export HOME="$app_path" + usermod --home "$app_path" "$unprivileged_user" >/dev/null 2>&1 + if [[ "$HEROKUISH_DISABLE_CHOWN" == "true" ]]; then + # unprivileged_user & unprivileged_group are defined in outer scope + # shellcheck disable=SC2154 + find "$app_path" \( \! -user "$unprivileged_user" -o \! -group "$unprivileged_group" \) -print0 | xargs -0 -r chown "$unprivileged_user:$unprivileged_group" + fi } diff --git a/include/slug.bash b/include/slug.bash index 9b7954eac..a198a2c27 100644 --- a/include/slug.bash +++ b/include/slug.bash @@ -1,54 +1,53 @@ - readonly slug_path="/tmp/slug.tgz" slug-import() { - declare desc="Import a gzipped slug tarball from URL or STDIN " - declare url="$1" - ensure-paths - # app_path defined in outer scope - # shellcheck disable=SC2154 - if [[ "$(ls -A "$app_path")" ]]; then - return 1 - elif [[ "$url" ]]; then - curl -s --retry 2 "$url" | tar -xzC "$app_path" - else - cat | tar -xzC "$app_path" - fi + declare desc="Import a gzipped slug tarball from URL or STDIN " + declare url="$1" + ensure-paths + # app_path defined in outer scope + # shellcheck disable=SC2154 + if [[ "$(ls -A "$app_path")" ]]; then + return 1 + elif [[ "$url" ]]; then + curl -s --retry 2 "$url" | tar -xzC "$app_path" + else + cat | tar -xzC "$app_path" + fi } slug-generate() { - declare desc="Generate a gzipped slug tarball from the current app" - ensure-paths - local compress_option="-z" - if which pigz > /dev/null; then - compress_option="--use-compress-program=pigz" - fi - local slugignore_option - if [[ -f "$app_path/.slugignore" ]]; then - slugignore_option="-X $app_path/.slugignore" - fi - # slugignore_option may be empty - # shellcheck disable=SC2086 - tar "$compress_option" $slugignore_option \ - --exclude='.git' \ - -C "$app_path" \ - -cf "$slug_path" \ - . - local slug_size - slug_size="$(du -Sh "$slug_path" | cut -f1)" - title "Compiled slug size is $slug_size" + declare desc="Generate a gzipped slug tarball from the current app" + ensure-paths + local compress_option="-z" + if which pigz >/dev/null; then + compress_option="--use-compress-program=pigz" + fi + local slugignore_option + if [[ -f "$app_path/.slugignore" ]]; then + slugignore_option="-X $app_path/.slugignore" + fi + # slugignore_option may be empty + # shellcheck disable=SC2086 + tar "$compress_option" $slugignore_option \ + --exclude='.git' \ + -C "$app_path" \ + -cf "$slug_path" \ + . + local slug_size + slug_size="$(du -Sh "$slug_path" | cut -f1)" + title "Compiled slug size is $slug_size" } slug-export() { - declare desc="Export generated slug tarball to URL (PUT) or STDOUT" - declare url="$1" - ensure-paths - if [[ ! -f "$slug_path" ]]; then - return 1 - fi - if [[ "$url" ]]; then - curl -0 -s -o /dev/null --retry 2 -X PUT -T "$slug_path" "$url" - else - cat "$slug_path" - fi + declare desc="Export generated slug tarball to URL (PUT) or STDOUT" + declare url="$1" + ensure-paths + if [[ ! -f "$slug_path" ]]; then + return 1 + fi + if [[ "$url" ]]; then + curl -0 -s -o /dev/null --retry 2 -X PUT -T "$slug_path" "$url" + else + cat "$slug_path" + fi } diff --git a/tests/functional/tests.sh b/tests/functional/tests.sh index 749efa621..a61b2a582 100644 --- a/tests/functional/tests.sh +++ b/tests/functional/tests.sh @@ -1,47 +1,50 @@ +# shellcheck shell=bash herokuish-test() { - declare name="$1" script="$2" - # shellcheck disable=SC2046,SC2154 - docker run $([[ "$CI" ]] || echo "--rm") -v "$PWD:/mnt" \ - "herokuish:dev" bash -c "set -e; $script" \ - || $T_fail "$name exited non-zero" + declare name="$1" script="$2" + # shellcheck disable=SC2046,SC2154 + docker run $([[ "$CI" ]] || echo "--rm") -v "$PWD:/mnt" \ + "herokuish:dev" bash -c "set -e; $script" \ + || $T_fail "$name exited non-zero" } fn-source() { - # use this if you want to write tests - # in functions instead of strings. - # see test-binary for trivial example - # shellcheck disable=SC2086 - declare -f $1 | tail -n +2 + # use this if you want to write tests + # in functions instead of strings. + # see test-binary for trivial example + # shellcheck disable=SC2086 + declare -f $1 | tail -n +2 } function cleanup { - echo "Tests cleanup" - local procfile - procfile="$(cd "$( dirname "${BASH_SOURCE[0]}")" && pwd )/Procfile" - if [[ -f "$procfile" ]]; then - rm -f "$procfile" - fi + echo "Tests cleanup" + local procfile + procfile="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/Procfile" + if [[ -f "$procfile" ]]; then + rm -f "$procfile" + fi } trap cleanup EXIT T_binary() { - _test-binary() { - herokuish - } - herokuish-test "test-binary" "$(fn-source _test-binary)" + _test-binary() { + # shellcheck disable=SC2317 + herokuish + } + herokuish-test "test-binary" "$(fn-source _test-binary)" } T_default-user() { - _test-user() { - id herokuishuser - } - herokuish-test "test-user" "$(fn-source _test-user)" + _test-user() { + # shellcheck disable=SC2317 + id herokuishuser + } + herokuish-test "test-user" "$(fn-source _test-user)" } T_generate-slug() { - herokuish-test "test-slug-generate" " + herokuish-test "test-slug-generate" " herokuish slug generate tar tzf /tmp/slug.tgz" } diff --git a/tests/unit/tests.sh b/tests/unit/tests.sh index 8733faff5..2e0d1190c 100644 --- a/tests/unit/tests.sh +++ b/tests/unit/tests.sh @@ -1,197 +1,201 @@ - -T_envfile-parse(){ - # shellcheck disable=SC1090 - source "$(dirname "${BASH_SOURCE[0]}")/../../include/buildpack.bash" - local fixture_filename - local foo_expected='Hello'$'\n'' '\''world'\'' ' - local bar_expected='te'\''st' - local nested_foo_expected=foo - local nested_bar_expected=foo - - fixture_filename="$(dirname "${BASH_SOURCE[0]}")/fixtures/complicated_envfile" - eval "$(cat "$fixture_filename" | _envfile-parse)" - - # shellcheck disable=2154 - if [[ ! "$foo_expected" == "$foo" ]]; then - echo "Expected foo = $foo_expected got: $foo" - return 1 - fi - - # shellcheck disable=2154 - if [[ ! "$bar_expected" == "$bar" ]]; then - echo "Expected bar = $bar_expected got: $bar" - return 2 - fi - - # shellcheck disable=2154 - if [[ ! "$nested_foo_expected" == "$nested_foo" ]]; then - echo "Expected nested_foo = $nested_foo_expected got: $nested_foo" - return 3 - fi - - # shellcheck disable=2154 - if [[ ! "$nested_bar_expected" == "$nested_bar" ]]; then - echo "Expected nested_bar = $nested_bar_expected got: $nested_bar" - return 4 - fi +# shellcheck shell=bash + +T_envfile-parse() { + # shellcheck disable=SC1091 + source "$(dirname "${BASH_SOURCE[0]}")/../../include/buildpack.bash" + local fixture_filename + local foo_expected='Hello'$'\n'' '\''world'\'' ' + local bar_expected='te'\''st' + local nested_foo_expected=foo + local nested_bar_expected=foo + + fixture_filename="$(dirname "${BASH_SOURCE[0]}")/fixtures/complicated_envfile" + eval "$(_envfile-parse <"$fixture_filename")" + + # shellcheck disable=2154 + if [[ ! "$foo_expected" == "$foo" ]]; then + echo "Expected foo = $foo_expected got: $foo" + return 1 + fi + + # shellcheck disable=2154 + if [[ ! "$bar_expected" == "$bar" ]]; then + echo "Expected bar = $bar_expected got: $bar" + return 2 + fi + + # shellcheck disable=2154 + if [[ ! "$nested_foo_expected" == "$nested_foo" ]]; then + echo "Expected nested_foo = $nested_foo_expected got: $nested_foo" + return 3 + fi + + # shellcheck disable=2154 + if [[ ! "$nested_bar_expected" == "$nested_bar" ]]; then + echo "Expected nested_bar = $nested_bar_expected got: $nested_bar" + return 4 + fi } T_procfile-parse-valid() { - # shellcheck disable=SC1090 - source "$(dirname "${BASH_SOURCE[0]}")/../../include/procfile.bash" - local expected actual app_path - app_path="$(dirname "${BASH_SOURCE[0]}")/fixtures" - for type in web worker; do - case "$type" in - web) - expected="npm start" - ;; - worker) - expected="npm worker" - ;; - esac - actual=$(procfile-parse "$type" | xargs) - if [[ "$actual" != "$expected" ]]; then - echo "$actual != $expected" - return 1 - fi - done + # shellcheck disable=SC1091 + source "$(dirname "${BASH_SOURCE[0]}")/../../include/procfile.bash" + local expected actual app_path + app_path="$(dirname "${BASH_SOURCE[0]}")/fixtures" + for type in web worker; do + case "$type" in + web) + expected="npm start" + ;; + worker) + expected="npm worker" + ;; + esac + actual=$(procfile-parse "$type" | xargs) + if [[ "$actual" != "$expected" ]]; then + echo "$actual != $expected" + return 1 + fi + done } T_procfile-parse-merge-conflict() { - # shellcheck disable=SC1090 - source "$(dirname "${BASH_SOURCE[0]}")/../../include/procfile.bash" - local expected actual app_path - app_path="$(dirname "${BASH_SOURCE[0]}")/fixtures-merge-conflict" - for type in web worker; do - case "$type" in - web) - expected="npm start" - ;; - worker) - expected="npm worker" - ;; - esac - actual=$(procfile-parse "$type" | xargs) - if [[ "$actual" != "$expected" ]]; then - echo "$actual != $expected" - return 1 - fi - done + # shellcheck disable=SC1091 + source "$(dirname "${BASH_SOURCE[0]}")/../../include/procfile.bash" + local expected actual app_path + app_path="$(dirname "${BASH_SOURCE[0]}")/fixtures-merge-conflict" + for type in web worker; do + case "$type" in + web) + expected="npm start" + ;; + worker) + expected="npm worker" + ;; + esac + actual=$(procfile-parse "$type" | xargs) + if [[ "$actual" != "$expected" ]]; then + echo "$actual != $expected" + return 1 + fi + done } T_procfile-parse-invalid() { - # shellcheck disable=SC1090 - source "$(dirname "${BASH_SOURCE[0]}")/../../include/procfile.bash" - local expected actual app_path - app_path="$(dirname "${BASH_SOURCE[0]}")/fixtures" - - expected="Proc entrypoint invalid-proc does not exist. Please check your Procfile" - actual="$(procfile-start invalid-proc)" - - if [[ "$actual" != "$expected" ]]; then - echo "procfile-start did not throw error for invalid procfile" - return 1 - fi + # shellcheck disable=SC1091 + source "$(dirname "${BASH_SOURCE[0]}")/../../include/procfile.bash" + local expected actual app_path + app_path="$(dirname "${BASH_SOURCE[0]}")/fixtures" + + expected="Proc entrypoint invalid-proc does not exist. Please check your Procfile" + actual="$(procfile-start invalid-proc)" + + if [[ "$actual" != "$expected" ]]; then + echo "procfile-start did not throw error for invalid procfile" + return 1 + fi } T_procfile-types() { - title() { - : - } - # shellcheck disable=SC1090 - source "$(dirname "${BASH_SOURCE[0]}")/../../include/procfile.bash" - local expected actual app_path - app_path="$(dirname "${BASH_SOURCE[0]}")/fixtures" - - expected="Procfile declares types -> web, worker" - actual="$(procfile-types invalid-proc | tail -1)" - - if [[ "$actual" != "$expected" ]]; then - echo "$actual != $expected" - return 1 - fi + title() { + # shellcheck disable=SC2317 + : + } + # shellcheck disable=SC1091 + source "$(dirname "${BASH_SOURCE[0]}")/../../include/procfile.bash" + local expected actual app_path + app_path="$(dirname "${BASH_SOURCE[0]}")/fixtures" + + expected="Procfile declares types -> web, worker" + actual="$(procfile-types invalid-proc | tail -1)" + + if [[ "$actual" != "$expected" ]]; then + echo "$actual != $expected" + return 1 + fi } T_procfile-types-merge-conflict() { - title() { - : - } - # shellcheck disable=SC1090 - source "$(dirname "${BASH_SOURCE[0]}")/../../include/procfile.bash" - local expected actual app_path - app_path="$(dirname "${BASH_SOURCE[0]}")/fixtures-merge-conflict" - - expected="Procfile declares types -> web, worker" - actual="$(procfile-types invalid-proc | tail -1)" - - if [[ "$actual" != "$expected" ]]; then - echo "$actual != $expected" - return 1 - fi + title() { + # shellcheck disable=SC2317 + : + } + # shellcheck disable=SC1091 + source "$(dirname "${BASH_SOURCE[0]}")/../../include/procfile.bash" + local expected actual app_path + app_path="$(dirname "${BASH_SOURCE[0]}")/fixtures-merge-conflict" + + expected="Procfile declares types -> web, worker" + actual="$(procfile-types invalid-proc | tail -1)" + + if [[ "$actual" != "$expected" ]]; then + echo "$actual != $expected" + return 1 + fi } T_procfile-load-env() { - # shellcheck disable=SC1090 - source "$(dirname "${BASH_SOURCE[0]}")/../../include/procfile.bash" - local expected actual app_path env_path - env_path="$(dirname "${BASH_SOURCE[0]}")/fixtures/env" - - procfile-load-env - actual="$TEST_BUILDPACK_URL" - expected="$(cat "$env_path/TEST_BUILDPACK_URL")" - - if [[ "$actual" != "$expected" ]]; then - echo "$actual != $expected" - return 1 - fi - unset TEST_BUILDPACK_URL + # shellcheck disable=SC1091 + source "$(dirname "${BASH_SOURCE[0]}")/../../include/procfile.bash" + local expected actual app_path env_path + env_path="$(dirname "${BASH_SOURCE[0]}")/fixtures/env" + + procfile-load-env + actual="$TEST_BUILDPACK_URL" + expected="$(cat "$env_path/TEST_BUILDPACK_URL")" + + if [[ "$actual" != "$expected" ]]; then + echo "$actual != $expected" + return 1 + fi + unset TEST_BUILDPACK_URL } T_procfile-load-profile() { - # shellcheck disable=SC1090 - source "$(dirname "${BASH_SOURCE[0]}")/../../include/procfile.bash" - local expected actual app_path - app_path="$(dirname "${BASH_SOURCE[0]}")/fixtures" - - procfile-load-profile - actual="$TEST_APP_TYPE" - expected="nodejs" - - if [[ "$actual" != "$expected" ]]; then - echo "$actual != $expected" - return 1 - fi + # shellcheck disable=SC1091 + source "$(dirname "${BASH_SOURCE[0]}")/../../include/procfile.bash" + local expected actual app_path + # shellcheck disable=SC2034 + app_path="$(dirname "${BASH_SOURCE[0]}")/fixtures" + + procfile-load-profile + actual="$TEST_APP_TYPE" + expected="nodejs" + + if [[ "$actual" != "$expected" ]]; then + echo "$actual != $expected" + return 1 + fi } #the following two tests needs to launch an invalid command, #or else shell is hijacked by suceeding exec, so rather than no test #it is better to pass a failing cmd, so that we can check we pass exec step T_procfile-exec() { - # shellcheck disable=SC1090 - source "$(dirname "${BASH_SOURCE[0]}")/../../include/procfile.bash" - local expected actual + # shellcheck disable=SC1091 + source "$(dirname "${BASH_SOURCE[0]}")/../../include/procfile.bash" + local expected actual - actual=procfile-exec invalid - expected=".*invalid: command not found.*" + actual=procfile-exec invalid + expected=".*invalid: command not found.*" - if [[ "$actual" =~ $expected ]]; then - echo "$actual =~ $expected" - return 1 - fi + if [[ "$actual" =~ $expected ]]; then + echo "$actual =~ $expected" + return 1 + fi } T_procfile-exec-setuidgid-optout() { - # shellcheck disable=SC1090 - source "$(dirname "${BASH_SOURCE[0]}")/../../include/procfile.bash" - local expected actual - - HEROKUISH_SETUIDGUID=false - actual=procfile-exec invalid - expected=".*invalid: command not found.*" - - if [[ "$actual" =~ $expected ]]; then - echo "$actual =~ $expected" - return 1 - fi + # shellcheck disable=SC1091 + source "$(dirname "${BASH_SOURCE[0]}")/../../include/procfile.bash" + local expected actual + + export HEROKUISH_SETUIDGUID=false + actual=procfile-exec invalid + expected=".*invalid: command not found.*" + + if [[ "$actual" =~ $expected ]]; then + echo "$actual =~ $expected" + return 1 + fi }