From 542cc513e82d8ee5a759e556ba045e4584d3bbf7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 28 Mar 2024 05:35:30 +0000 Subject: [PATCH 01/17] chore(deps): bump actions/download-artifact from 3 to 4 Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 3 to 4. - [Release notes](https://github.com/actions/download-artifact/releases) - [Commits](https://github.com/actions/download-artifact/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/download-artifact dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/main.yml | 2 +- .github/workflows/tag-release.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f60747b8e..c08d9085b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -125,7 +125,7 @@ jobs: go-version: 1.17.8 - name: download packages - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: build-${{ matrix.heroku }}-false path: build diff --git a/.github/workflows/tag-release.yml b/.github/workflows/tag-release.yml index 5c8455449..9f04ed009 100644 --- a/.github/workflows/tag-release.yml +++ b/.github/workflows/tag-release.yml @@ -68,7 +68,7 @@ jobs: ruby-version: 3.3 - name: download packages - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: build-22-false path: build From 7e222832d961f48485235fff104159cadc2cd6a9 Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Thu, 28 Mar 2024 02:47:04 -0400 Subject: [PATCH 02/17] chore(deps): bump actions/upload-artifact from 3 to 4 --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c08d9085b..e34a9bdb6 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -87,7 +87,7 @@ jobs: fi - name: upload packages - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: build-${{ matrix.heroku }}-${{ matrix.buildx }} path: build From 37449a4d01e12ac6581ef6318e5f454270de3f15 Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Thu, 28 Mar 2024 02:47:19 -0400 Subject: [PATCH 03/17] chore(deps): bump actions/upload-artifact from 3 to 4 --- .github/workflows/tag-release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tag-release.yml b/.github/workflows/tag-release.yml index 9f04ed009..d3f073712 100644 --- a/.github/workflows/tag-release.yml +++ b/.github/workflows/tag-release.yml @@ -50,7 +50,7 @@ jobs: make build build/docker/${{ matrix.heroku }} BUILDX=false STACK_VERSION=${{ matrix.heroku }} - name: upload packages - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: build-${{ matrix.heroku }}-${{ matrix.buildx }} path: build From ff89948f1c1b11a427ca391632200e5d93d0b7b9 Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Thu, 28 Mar 2024 06:43:50 -0400 Subject: [PATCH 04/17] Use find to identify only files not already owned by user --- include/buildpack.bash | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/buildpack.bash b/include/buildpack.bash index f53ddf1a4..47889eeef 100644 --- a/include/buildpack.bash +++ b/include/buildpack.bash @@ -161,7 +161,7 @@ buildpack-setup() { # Prepare permissions quicker for slower filesystems # vars defined in outer scope # shellcheck disable=SC2154 - chown -R "$unprivileged_user:$unprivileged_group" "$app_path" + find "$app_path" \( \! -user "$unprivileged_user" -o \! -group "$unprivileged_group" \) -print0 | xargs -0 -r chown "$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 From f6c84700aa12fc76681936d2e60a55406dc229d1 Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Thu, 28 Mar 2024 06:45:08 -0400 Subject: [PATCH 05/17] chore: sync chown commands --- include/buildpack.bash | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/buildpack.bash b/include/buildpack.bash index 47889eeef..dd3cbb164 100644 --- a/include/buildpack.bash +++ b/include/buildpack.bash @@ -161,7 +161,7 @@ buildpack-setup() { # 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 -0 -r chown "$unprivileged_user:$unprivileged_group" + 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 From 11315542c640f98b1e30ca355c780dab75a6313e Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Thu, 28 Mar 2024 08:57:13 -0400 Subject: [PATCH 06/17] chore: run shfmt This is run using the same shfmt settings we have in dokku: 'shfmt -l -bn -ci -i 2 -w .' Additionally, ensure linters are added to github actions for testing in CI. --- .github/linters/.hadolint.yml | 6 + .github/linters/.markdown-lint.yml | 37 +++ .github/linters/.yamllint.yml | 8 + .github/workflows/lint.yml | 77 ++++++ Dockerfile | 8 +- buildpacks/test | 31 ++- contrib/post-install | 4 +- include/buildpack.bash | 408 +++++++++++++++-------------- include/cmd.bash | 113 ++++---- include/default_user.bash | 4 +- include/fn.bash | 34 +-- include/herokuish.bash | 224 ++++++++-------- include/procfile.bash | 200 +++++++------- include/slug.bash | 87 +++--- tests/functional/tests.sh | 51 ++-- tests/unit/tests.sh | 327 ++++++++++++----------- 16 files changed, 873 insertions(+), 746 deletions(-) create mode 100644 .github/linters/.hadolint.yml create mode 100644 .github/linters/.markdown-lint.yml create mode 100644 .github/linters/.yamllint.yml create mode 100644 .github/workflows/lint.yml 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..be1b4a4b8 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,77 @@ +--- +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 + + 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/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/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..93f0cb70e 100644 --- a/include/buildpack.bash +++ b/include/buildpack.bash @@ -1,229 +1,231 @@ - _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 + \'* | \"*) + 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 + 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 } 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..96f0d805c 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..5bee2f9f5 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..d9c61d8c4 100644 --- a/tests/functional/tests.sh +++ b/tests/functional/tests.sh @@ -1,47 +1,46 @@ - 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() { + 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() { + 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..e03ceb066 100644 --- a/tests/unit/tests.sh +++ b/tests/unit/tests.sh @@ -1,197 +1,196 @@ - -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 +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 } 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=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 } 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=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 } 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=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 } 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=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 } 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=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 } 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=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 } 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=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 } #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=SC1090 + 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=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 } From b3d94a44452ae758b53ab579a258372205e932e2 Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Thu, 28 Mar 2024 09:22:29 -0400 Subject: [PATCH 07/17] fix: correct lint errors --- .shellcheckrc | 7 +++++ CHANGELOG.md | 4 +-- README.md | 14 ++++----- .../tests/clojure-ring/test.sh | 8 +++-- buildpacks/buildpack-go/tests/go/test.sh | 6 ++-- .../buildpack-gradle/tests/gradle/test.sh | 6 ++-- .../buildpack-java/tests/java-jetty/test.sh | 6 ++-- .../buildpack-multi/tests/multi/test.sh | 6 ++-- .../tests/nodejs-express/test.sh | 6 ++-- buildpacks/buildpack-null/tests/null/test.sh | 6 ++-- buildpacks/buildpack-php/tests/php/README.md | 10 +++---- buildpacks/buildpack-play/tests/play/test.sh | 6 ++-- .../tests/python-django/test.sh | 6 ++-- .../tests/python-flask/test.sh | 6 ++-- .../buildpack-ruby/tests/ruby-sinatra/test.sh | 8 +++-- .../buildpack-scala/tests/scala/test.sh | 6 ++-- .../buildpack-static/tests/static/test.sh | 6 ++-- include/buildpack.bash | 6 ++-- include/fn.bash | 2 +- include/procfile.bash | 4 +-- tests/functional/tests.sh | 4 +++ tests/unit/tests.sh | 29 +++++++++++-------- 22 files changed, 103 insertions(+), 59 deletions(-) create mode 100644 .shellcheckrc 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/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/include/buildpack.bash b/include/buildpack.bash index 93f0cb70e..e6aad56e4 100644 --- a/include/buildpack.bash +++ b/include/buildpack.bash @@ -10,6 +10,7 @@ _envfile-parse() { value="${line#*=}" case "$value" in \'* | \"*) + # shellcheck disable=SC2269 value="${value}" ;; *) @@ -45,14 +46,15 @@ _select-buildpack() { 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") + 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 diff --git a/include/fn.bash b/include/fn.bash index 96f0d805c..3a6fa9eb1 100644 --- a/include/fn.bash +++ b/include/fn.bash @@ -9,7 +9,7 @@ fn-desc() { declare desc="Inspect a function's description" desc="" eval "$(type "$1" | grep desc | head -1)" - echo $desc + echo "$desc" } fn-info() { diff --git a/include/procfile.bash b/include/procfile.bash index 5bee2f9f5..e306ce467 100644 --- a/include/procfile.bash +++ b/include/procfile.bash @@ -88,7 +88,7 @@ procfile-load-env() { # shellcheck disable=SC2154 if [[ -d "$env_path" ]]; then shopt -s nullglob - for e in $env_path/*; do + for e in "$env_path"/*; do varname=$(basename "$e") export "$varname=$(cat "$e")" done @@ -102,7 +102,7 @@ procfile-load-profile() { source "$file" done mkdir -p "$app_path/.profile.d" - for file in $app_path/.profile.d/*.sh; do + for file in "$app_path/.profile.d"/*.sh; do # shellcheck disable=SC1090 source "$file" done diff --git a/tests/functional/tests.sh b/tests/functional/tests.sh index d9c61d8c4..a61b2a582 100644 --- a/tests/functional/tests.sh +++ b/tests/functional/tests.sh @@ -1,3 +1,5 @@ +# shellcheck shell=bash + herokuish-test() { declare name="$1" script="$2" # shellcheck disable=SC2046,SC2154 @@ -27,6 +29,7 @@ trap cleanup EXIT T_binary() { _test-binary() { + # shellcheck disable=SC2317 herokuish } herokuish-test "test-binary" "$(fn-source _test-binary)" @@ -34,6 +37,7 @@ T_binary() { T_default-user() { _test-user() { + # shellcheck disable=SC2317 id herokuishuser } herokuish-test "test-user" "$(fn-source _test-user)" diff --git a/tests/unit/tests.sh b/tests/unit/tests.sh index e03ceb066..2e0d1190c 100644 --- a/tests/unit/tests.sh +++ b/tests/unit/tests.sh @@ -1,5 +1,7 @@ +# shellcheck shell=bash + T_envfile-parse() { - # shellcheck disable=SC1090 + # shellcheck disable=SC1091 source "$(dirname "${BASH_SOURCE[0]}")/../../include/buildpack.bash" local fixture_filename local foo_expected='Hello'$'\n'' '\''world'\'' ' @@ -8,7 +10,7 @@ T_envfile-parse() { local nested_bar_expected=foo fixture_filename="$(dirname "${BASH_SOURCE[0]}")/fixtures/complicated_envfile" - eval "$(cat "$fixture_filename" | _envfile-parse)" + eval "$(_envfile-parse <"$fixture_filename")" # shellcheck disable=2154 if [[ ! "$foo_expected" == "$foo" ]]; then @@ -36,7 +38,7 @@ T_envfile-parse() { } T_procfile-parse-valid() { - # shellcheck disable=SC1090 + # shellcheck disable=SC1091 source "$(dirname "${BASH_SOURCE[0]}")/../../include/procfile.bash" local expected actual app_path app_path="$(dirname "${BASH_SOURCE[0]}")/fixtures" @@ -58,7 +60,7 @@ T_procfile-parse-valid() { } T_procfile-parse-merge-conflict() { - # shellcheck disable=SC1090 + # 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" @@ -80,7 +82,7 @@ T_procfile-parse-merge-conflict() { } T_procfile-parse-invalid() { - # shellcheck disable=SC1090 + # shellcheck disable=SC1091 source "$(dirname "${BASH_SOURCE[0]}")/../../include/procfile.bash" local expected actual app_path app_path="$(dirname "${BASH_SOURCE[0]}")/fixtures" @@ -96,9 +98,10 @@ T_procfile-parse-invalid() { T_procfile-types() { title() { + # shellcheck disable=SC2317 : } - # shellcheck disable=SC1090 + # shellcheck disable=SC1091 source "$(dirname "${BASH_SOURCE[0]}")/../../include/procfile.bash" local expected actual app_path app_path="$(dirname "${BASH_SOURCE[0]}")/fixtures" @@ -114,9 +117,10 @@ T_procfile-types() { T_procfile-types-merge-conflict() { title() { + # shellcheck disable=SC2317 : } - # shellcheck disable=SC1090 + # 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" @@ -131,7 +135,7 @@ T_procfile-types-merge-conflict() { } T_procfile-load-env() { - # shellcheck disable=SC1090 + # 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" @@ -148,9 +152,10 @@ T_procfile-load-env() { } T_procfile-load-profile() { - # shellcheck disable=SC1090 + # 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 @@ -167,7 +172,7 @@ T_procfile-load-profile() { #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 + # shellcheck disable=SC1091 source "$(dirname "${BASH_SOURCE[0]}")/../../include/procfile.bash" local expected actual @@ -181,11 +186,11 @@ T_procfile-exec() { } T_procfile-exec-setuidgid-optout() { - # shellcheck disable=SC1090 + # shellcheck disable=SC1091 source "$(dirname "${BASH_SOURCE[0]}")/../../include/procfile.bash" local expected actual - HEROKUISH_SETUIDGUID=false + export HEROKUISH_SETUIDGUID=false actual=procfile-exec invalid expected=".*invalid: command not found.*" From 2d654e87459b36ddd23056e2bc29101b89b1af9a Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Thu, 28 Mar 2024 09:24:10 -0400 Subject: [PATCH 08/17] fix: ignore path --- .github/workflows/lint.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index be1b4a4b8..e20f014ce 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -51,6 +51,9 @@ jobs: 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 From ce6a3705693b5606c14bd8c242f1cc84289e2c31 Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Thu, 28 Mar 2024 09:25:07 -0400 Subject: [PATCH 09/17] chore: remove lint call --- .github/workflows/main.yml | 3 --- Makefile | 12 ------------ 2 files changed, 15 deletions(-) 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/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) From f2e9c4089666ffed867eda8cf567ede57a494830 Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Thu, 28 Mar 2024 09:26:05 -0400 Subject: [PATCH 10/17] fix: use correct path --- .github/workflows/lint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index e20f014ce..858d0cc6b 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -53,7 +53,7 @@ jobs: uses: ludeeus/action-shellcheck@00cae500b08a931fb5698e11e79bfbd38e612a38 with: ignore_paths: >- - tests/unit/fixtures/.profile.d/app.sh + ./tests/unit/fixtures/.profile.d/app.sh shfmt: name: shfmt From e9232afe6852fcfda72d924fe5b6b43d925d5b9e Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Thu, 28 Mar 2024 08:52:48 -0400 Subject: [PATCH 11/17] fix: ensure all file permissions are set to specified unprivileged user This change avoids a potentially heavy chown operation at the start of the container process - in fact, it may even allow us to drop perm changes completely - by ensuring any created files are _always_ set to the correct permissions. --- include/buildpack.bash | 9 +++++++-- include/procfile.bash | 7 ++++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/include/buildpack.bash b/include/buildpack.bash index e6aad56e4..9b9dc25fc 100644 --- a/include/buildpack.bash +++ b/include/buildpack.bash @@ -162,6 +162,9 @@ buildpack-setup() { # shellcheck disable=SC2154 usermod --home "$HOME" "$unprivileged_user" >/dev/null 2>&1 + # shellcheck disable=SC2154 + chown "$unprivileged_user:$unprivileged_group" "$HOME" + # Prepare permissions quicker for slower filesystems # vars defined in outer scope # shellcheck disable=SC2154 @@ -191,16 +194,18 @@ buildpack-execute() { 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" + unprivileged "$selected_path/bin/release" "$build_path" "$cache_path" | unprivileged tee "$build_path/.release" >/dev/null fi if [[ -f "$build_path/.release" ]]; then config_vars="$(cat "$build_path/.release" | yaml-get config_vars)" + unprivileged touch "$build_path/.profile.d/00_config_vars.sh" if [[ "$config_vars" ]]; then mkdir -p "$build_path/.profile.d" + chown "$unprivileged_user:$unprivileged_group" "$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" + echo "export $(echo "$var" | sed -e 's/=/="/' -e 's/$/"/')" | unprivileged tee -a "$build_path/.profile.d/00_config_vars.sh" >/dev/null done IFS=$OIFS fi diff --git a/include/procfile.bash b/include/procfile.bash index e306ce467..55abede23 100644 --- a/include/procfile.bash +++ b/include/procfile.bash @@ -75,7 +75,8 @@ procfile-types() { # 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" + unprivileged touch "$app_path/Procfile" + echo "$type: $(cat "$app_path/.release" | yaml-get default_process_types "$type")" | unprivileged tee -a "$app_path/Procfile" >/dev/null done return fi @@ -102,6 +103,7 @@ procfile-load-profile() { source "$file" done mkdir -p "$app_path/.profile.d" + chown "$unprivileged_user:$unprivileged_group" "$app_path/.profile.d" for file in "$app_path/.profile.d"/*.sh; do # shellcheck disable=SC1090 source "$file" @@ -116,7 +118,10 @@ procfile-load-profile() { procfile-setup-home() { export HOME="$app_path" + # shellcheck disable=SC2154 usermod --home "$app_path" "$unprivileged_user" >/dev/null 2>&1 + # shellcheck disable=SC2154 + chown "$unprivileged_user:$unprivileged_group" "$app_path" if [[ "$HEROKUISH_DISABLE_CHOWN" == "true" ]]; then # unprivileged_user & unprivileged_group are defined in outer scope # shellcheck disable=SC2154 From fa8df04ba2ffe710e004600e80b7228d12acf814 Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Thu, 28 Mar 2024 15:42:21 -0400 Subject: [PATCH 12/17] fix: correct lint issue --- include/procfile.bash | 1 + 1 file changed, 1 insertion(+) diff --git a/include/procfile.bash b/include/procfile.bash index 55abede23..c53270c2a 100644 --- a/include/procfile.bash +++ b/include/procfile.bash @@ -103,6 +103,7 @@ procfile-load-profile() { source "$file" done mkdir -p "$app_path/.profile.d" + # shellcheck disable=SC2154 chown "$unprivileged_user:$unprivileged_group" "$app_path/.profile.d" for file in "$app_path/.profile.d"/*.sh; do # shellcheck disable=SC1090 From e1877f577808b07e961e646dcecbf4a2101649c4 Mon Sep 17 00:00:00 2001 From: Matthew Landauer Date: Wed, 17 Jul 2019 05:10:21 +1000 Subject: [PATCH 13/17] Only copy from app import path (e.g. /tmp/app) to build path (e.g. /app) when building --- include/buildpack.bash | 5 +++++ include/herokuish.bash | 4 ---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/include/buildpack.bash b/include/buildpack.bash index 9b9dc25fc..090282a12 100644 --- a/include/buildpack.bash +++ b/include/buildpack.bash @@ -145,6 +145,11 @@ buildpack-list() { } buildpack-setup() { + # shellcheck disable=SC2154 + if [[ -d "$import_path" ]] && [[ -n "$(ls -A "$import_path")" ]]; then + rm -rf "$app_path" && cp -r "$import_path" "$app_path" + fi + # Buildpack expectations # app_path defined in outer scope # shellcheck disable=SC2154 diff --git a/include/herokuish.bash b/include/herokuish.bash index bccb358fa..228a54730 100644 --- a/include/herokuish.bash +++ b/include/herokuish.bash @@ -123,10 +123,6 @@ 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 From 3beadaacfeb3399ff6a2581518758764e03bc5f5 Mon Sep 17 00:00:00 2001 From: Matthew Landauer Date: Thu, 18 Jul 2019 09:53:59 +1000 Subject: [PATCH 14/17] $import_path is defined in outer scope. --- include/buildpack.bash | 1 + 1 file changed, 1 insertion(+) diff --git a/include/buildpack.bash b/include/buildpack.bash index 090282a12..fd7c29bb0 100644 --- a/include/buildpack.bash +++ b/include/buildpack.bash @@ -145,6 +145,7 @@ buildpack-list() { } buildpack-setup() { + # $import_path is defined in outer scope # shellcheck disable=SC2154 if [[ -d "$import_path" ]] && [[ -n "$(ls -A "$import_path")" ]]; then rm -rf "$app_path" && cp -r "$import_path" "$app_path" From 7a1c10f234c1e5816c56ee4e04f9e373e153f9af Mon Sep 17 00:00:00 2001 From: Matthew Landauer Date: Tue, 23 Jul 2019 03:35:19 +1000 Subject: [PATCH 15/17] Formatting change only. Switch from using spaces to tabs. --- include/buildpack.bash | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/buildpack.bash b/include/buildpack.bash index fd7c29bb0..ae9fb1abf 100644 --- a/include/buildpack.bash +++ b/include/buildpack.bash @@ -145,11 +145,11 @@ buildpack-list() { } buildpack-setup() { - # $import_path is defined in outer scope - # shellcheck disable=SC2154 - if [[ -d "$import_path" ]] && [[ -n "$(ls -A "$import_path")" ]]; then - rm -rf "$app_path" && cp -r "$import_path" "$app_path" - fi + # $import_path is defined in outer scope + # shellcheck disable=SC2154 + if [[ -d "$import_path" ]] && [[ -n "$(ls -A "$import_path")" ]]; then + rm -rf "$app_path" && cp -r "$import_path" "$app_path" + fi # Buildpack expectations # app_path defined in outer scope From 80904f5ea6894e1e755b48e6653e3dd44646e030 Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Thu, 28 Mar 2024 17:29:26 -0400 Subject: [PATCH 16/17] fix: correct lint issue --- include/buildpack.bash | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/buildpack.bash b/include/buildpack.bash index ae9fb1abf..fd7c29bb0 100644 --- a/include/buildpack.bash +++ b/include/buildpack.bash @@ -145,11 +145,11 @@ buildpack-list() { } buildpack-setup() { - # $import_path is defined in outer scope - # shellcheck disable=SC2154 - if [[ -d "$import_path" ]] && [[ -n "$(ls -A "$import_path")" ]]; then - rm -rf "$app_path" && cp -r "$import_path" "$app_path" - fi + # $import_path is defined in outer scope + # shellcheck disable=SC2154 + if [[ -d "$import_path" ]] && [[ -n "$(ls -A "$import_path")" ]]; then + rm -rf "$app_path" && cp -r "$import_path" "$app_path" + fi # Buildpack expectations # app_path defined in outer scope From 1e44d1520330308a38ea79e57f48572382556ebe Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Thu, 28 Mar 2024 18:18:55 -0400 Subject: [PATCH 17/17] Release 0.8.0 - #1093 @dependabot: chore(deps): bump actions/download-artifact from 3 to 4 - #1173 @josegonzalez: Use find to identify only files not already owned by user - #1174 @josegonzalez: Add linting to CI - #1175 @josegonzalez: Ensure all file permissions are set to specified unprivileged user - #467 @mlandauer: Only copy from app import path to app path when building --- CHANGELOG.md | 8 ++++++++ Makefile | 2 +- README.md | 4 ++-- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f856fd6cf..9db71066c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ All notable changes to this project will be documented in this file. +## [0.8.0](https://github.com/gliderlabs/herokuish/compare/v0.7.6...v0.8.0) - 2024-03-28 + +- #1093 @dependabot: chore(deps): bump actions/download-artifact from 3 to 4 +- #1173 @josegonzalez: Use find to identify only files not already owned by user +- #1174 @josegonzalez: Add linting to CI +- #1175 @josegonzalez: Ensure all file permissions are set to specified unprivileged user +- #467 @mlandauer: Only copy from app import path to app path when building + ## [0.7.6](https://github.com/gliderlabs/herokuish/compare/v0.7.5...v0.7.6) - 2024-03-28 - #1171 @josegonzalez: Use a run mount to add build dependencies diff --git a/Makefile b/Makefile index dc76b33a5..6cd461c82 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ REPOSITORY = herokuish DESCRIPTION = 'Herokuish uses Docker and Buildpacks to build applications like Heroku' HARDWARE = $(shell uname -m) SYSTEM_NAME = $(shell uname -s | tr '[:upper:]' '[:lower:]') -VERSION ?= 0.7.6 +VERSION ?= 0.8.0 IMAGE_NAME ?= $(NAME) BUILD_TAG ?= dev PACKAGECLOUD_REPOSITORY ?= dokku/dokku-betafish diff --git a/README.md b/README.md index f4e6b8e63..bd41b2cdd 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![Build Status](https://github.com/gliderlabs/herokuish/workflows/CI/badge.svg)](https://github.com/gliderlabs/herokuish/actions?query=workflow%3ACI) [![IRC Channel](https://img.shields.io/badge/irc-%23gliderlabs-blue.svg)](https://kiwiirc.com/client/irc.freenode.net/#gliderlabs) -[![Docker Hub](https://img.shields.io/badge/docker%20hub-v0.7.6-blue)](https://hub.docker.com/r/gliderlabs/herokuish) +[![Docker Hub](https://img.shields.io/badge/docker%20hub-v0.8.0-blue)](https://hub.docker.com/r/gliderlabs/herokuish) A command line tool for emulating Heroku build and runtime tasks in containers. @@ -19,7 +19,7 @@ Download and uncompress the latest binary tarball from [releases](https://github For example, you can do this directly in your Dockerfiles installing into `/bin` as one step: ```shell -RUN curl --location --silent https://github.com/gliderlabs/herokuish/releases/download/v0.7.6/herokuish_0.7.6_linux_x86_64.tgz \ +RUN curl --location --silent https://github.com/gliderlabs/herokuish/releases/download/v0.8.0/herokuish_0.8.0_linux_x86_64.tgz \ | tar -xzC /bin ```