From fe6a0f796e034e3f1ccc00709e178615ed950509 Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Sun, 27 Aug 2023 12:36:50 -0400 Subject: [PATCH] feat: add support for nixpacks as a builder Closes #5338 --- docs/deployment/builders/nixpacks.md | 155 ++++++++++++++++++ plugins/builder-nixpacks/builder-build | 67 ++++++++ plugins/builder-nixpacks/builder-detect | 17 ++ plugins/builder-nixpacks/builder-release | 31 ++++ plugins/builder-nixpacks/commands | 15 ++ plugins/builder-nixpacks/core-post-extract | 30 ++++ .../dockerfiles/builder-build.Dockerfile | 7 + .../dockerfiles/builder-release.Dockerfile | 2 + plugins/builder-nixpacks/help-functions | 33 ++++ plugins/builder-nixpacks/install | 16 ++ plugins/builder-nixpacks/internal-functions | 116 +++++++++++++ plugins/builder-nixpacks/plugin.toml | 4 + plugins/builder-nixpacks/post-app-clone-setup | 14 ++ .../builder-nixpacks/post-app-rename-setup | 15 ++ plugins/builder-nixpacks/post-delete | 15 ++ plugins/builder-nixpacks/report | 6 + plugins/builder-nixpacks/subcommands/default | 6 + plugins/builder-nixpacks/subcommands/report | 6 + plugins/builder-nixpacks/subcommands/set | 30 ++++ tests/unit/builder-nixpacks.bats | 52 ++++++ tests/unit/test_helper.bash | 16 +- 21 files changed, 648 insertions(+), 5 deletions(-) create mode 100644 docs/deployment/builders/nixpacks.md create mode 100755 plugins/builder-nixpacks/builder-build create mode 100755 plugins/builder-nixpacks/builder-detect create mode 100755 plugins/builder-nixpacks/builder-release create mode 100755 plugins/builder-nixpacks/commands create mode 100755 plugins/builder-nixpacks/core-post-extract create mode 100644 plugins/builder-nixpacks/dockerfiles/builder-build.Dockerfile create mode 100644 plugins/builder-nixpacks/dockerfiles/builder-release.Dockerfile create mode 100755 plugins/builder-nixpacks/help-functions create mode 100755 plugins/builder-nixpacks/install create mode 100755 plugins/builder-nixpacks/internal-functions create mode 100644 plugins/builder-nixpacks/plugin.toml create mode 100755 plugins/builder-nixpacks/post-app-clone-setup create mode 100755 plugins/builder-nixpacks/post-app-rename-setup create mode 100755 plugins/builder-nixpacks/post-delete create mode 100755 plugins/builder-nixpacks/report create mode 100755 plugins/builder-nixpacks/subcommands/default create mode 100755 plugins/builder-nixpacks/subcommands/report create mode 100755 plugins/builder-nixpacks/subcommands/set create mode 100644 tests/unit/builder-nixpacks.bats diff --git a/docs/deployment/builders/nixpacks.md b/docs/deployment/builders/nixpacks.md new file mode 100644 index 000000000..0d6421f53 --- /dev/null +++ b/docs/deployment/builders/nixpacks.md @@ -0,0 +1,155 @@ +# Nixpacks + +> New as of 0.32.0 + +The `nixpacks` builder builds apps via [Nixpacks](https://nixpacks.com/), a buildpack alternative. + +## Usage + +### Requirements + +The `nixpacks` cli tool is not included by default with Dokku or as a dependency. It must also be installed as shown on [this page](https://nixpacks.com/docs/install#debian-(and-derivatives-like-ubuntu)). + +Builds will proceed with the `nixpacks` cli for the app from then on. + +### Detection + +This builder will be auto-detected in the following case: + +- A `nixpacks.toml` exists in the root of the app repository. + +The builder may also be selected via the `builder:set` command + +```shell +dokku builder:set node-js-app selected nixpacks +``` + +### Supported languages + +See the [upstream nixpacks documentation](https://nixpacks.com/docs) for further information on what languages and frameworks are supported. + +### Build-time configuration variables + +For security reasons - and as per [Docker recommendations](https://github.com/docker/docker/issues/13490) - nixpacks-based deploys have variables available only during runtime. + +For users that require customization in the `build` phase, you may use build arguments via the [docker-options plugin](/docs/advanced-usage/docker-options.md). All environment variables set by the `config` plugin are automatically exported within the nixpacks build environment, and thus `--env` only requires setting a key without a value. + +```shell +dokku docker-options:add node-js-app build '--env NODE_ENV' +``` + +Alternatively, a full value may be provided in the form of `--env KEY=VALUE`: + +```shell +dokku docker-options:add node-js-app build '--env NODE_ENV=production' +``` + +### Changing the `nixpacks.toml` location + +When deploying a monorepo, it may be desirable to specify the specific path of the `nixpacks.toml` file to use for a given app. This can be done via the `builder-nixpacks:set` command. If a value is specified and that file does not exist in the app's build directory, then the build will fail. + +```shell +dokku builder-nixpacks:set node-js-app nixpackstoml-path nixpacks2.toml +``` + +The default value may be set by passing an empty value for the option: + +```shell +dokku builder-nixpacks:set node-js-app nixpackstoml-path +``` + +The `nixpackstoml-path` property can also be set globally. The global default is `nixpacks.toml`, and the global value is used when no app-specific value is set. + +```shell +dokku builder-nixpacks:set --global nixpackstoml-path nixpacks2.toml +``` + +The default value may be set by passing an empty value for the option. + +```shell +dokku builder-nixpacks:set --global nixpackstoml-path +``` + +### Disabling cache + +Cache is enabled by default, but can be disabled by setting the `no-cache` property to `true`: + +```shell +dokku builder-nixpacks:set node-js-app no-cache true +``` + +The default value may be set by passing an empty value for the option: + +```shell +dokku builder-nixpacks:set node-js-app no-cache +``` + +The `no-cache` property can also be set globally. The global default is `false`, and the global value is used when no app-specific value is set. + +```shell +dokku builder-nixpacks:set --global no-cache true +``` + +The default value may be set by passing an empty value for the option. + +```shell +dokku builder-nixpacks:set --global no-cache +``` + +### Displaying builder-nixpacks reports for an app + +You can get a report about the app's storage status using the `builder-nixpacks:report` command: + +```shell +dokku builder-nixpacks:report +``` + +``` +=====> node-js-app builder-nixpacks information + Builder-nixpacks computed nixpackstoml path: nixpacks2.toml + Builder-nixpacks global nixpackstoml path: nixpacks.toml + Builder-nixpacks nixpackstoml path: nixpacks2.toml + Builder-nixpacks computed no cache: true + Builder-nixpacks global no cache: false + Builder-nixpacks no cache: true +=====> python-sample builder-nixpacks information + Builder-nixpacks computed nixpackstoml path: nixpacks.toml + Builder-nixpacks global nixpackstoml path: nixpacks.toml + Builder-nixpacks nixpackstoml path: + Builder-nixpacks computed no cache: false + Builder-nixpacks global no cache: false + Builder-nixpacks no cache: +=====> ruby-sample builder-nixpacks information + Builder-nixpacks computed nixpackstoml path: nixpacks.toml + Builder-nixpacks global nixpackstoml path: nixpacks.toml + Builder-nixpacks nixpackstoml path: + Builder-nixpacks computed no cache: false + Builder-nixpacks global no cache: false + Builder-nixpacks no cache: +``` + +You can run the command for a specific app also. + +```shell +dokku builder-nixpacks:report node-js-app +``` + +``` +=====> node-js-app builder-nixpacks information + Builder-nixpacks computed nixpackstoml path: nixpacks2.toml + Builder-nixpacks global nixpackstoml path: nixpacks.toml + Builder-nixpacks nixpackstoml path: nixpacks2.toml + Builder-nixpacks computed no cache: true + Builder-nixpacks global no cache: false + Builder-nixpacks no cache: true +``` + +You can pass flags which will output only the value of the specific information you want. For example: + +```shell +dokku builder-nixpacks:report node-js-app --builder-nixpacks-no-cache +``` + +``` +true +``` diff --git a/plugins/builder-nixpacks/builder-build b/plugins/builder-nixpacks/builder-build new file mode 100755 index 000000000..eae65baba --- /dev/null +++ b/plugins/builder-nixpacks/builder-build @@ -0,0 +1,67 @@ +#!/usr/bin/env bash +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_AVAILABLE_PATH/builder-nixpacks/internal-functions" +source "$PLUGIN_AVAILABLE_PATH/config/functions" +set -eo pipefail +[[ $DOKKU_TRACE ]] && set -x + +trigger-builder-nixpacks-builder-build() { + declare desc="builder-nixpacks builder-build plugin trigger" + declare trigger="builder-build" + declare BUILDER_TYPE="$1" APP="$2" SOURCECODE_WORK_DIR="$3" + + if [[ "$BUILDER_TYPE" != "nixpacks" ]]; then + return + fi + + dokku_log_info1 "Building $APP from nixpacks" + + if ! command -v "nixpacks" &>/dev/null; then + dokku_log_fail "Missing nixpacks, install it" + fi + + local IMAGE=$(get_app_image_name "$APP") + local DOCKER_BUILD_LABEL_ARGS=("--label=dokku" "--label=org.label-schema.schema-version=1.0" "--label=org.label-schema.vendor=dokku" "--label=com.dokku.image-stage=build" "--label=com.dokku.builder-type=dockerfile" "--label=com.dokku.app-name=$APP") + + pushd "$SOURCECODE_WORK_DIR" &>/dev/null + + plugn trigger pre-build "$BUILDER_TYPE" "$APP" "$SOURCECODE_WORK_DIR" + + no_cache="$(fn-builder-nixpacks-computed-no-cache "$APP")" + NIXPACKS_ARGS="" + if [[ "$no_cache" == "true" ]]; then + NIXPACKS_ARGS="$NIXPACKS_ARGS --no-cache" + fi + + local DOCKER_ARGS=$(: | plugn trigger docker-args-build "$APP" "$BUILDER_TYPE") + DOCKER_ARGS+=$(: | plugn trigger docker-args-process-build "$APP" "$BUILDER_TYPE") + + # strip --link, --volume and -v args from DOCKER_ARGS + local DOCKER_ARGS=$(sed -e "s/^--link=[[:graph:]]\+[[:blank:]]\?//g" -e "s/^--link[[:blank:]]\?[[:graph:]]\+[[:blank:]]\?//g" -e "s/^--volume=[[:graph:]]\+[[:blank:]]\?//g" -e "s/^--volume[[:blank:]]\?[[:graph:]]\+[[:blank:]]\?//g" -e "s/^-v[[:blank:]]\?[[:graph:]]\+[[:blank:]]\?//g" <<<"$DOCKER_ARGS") + declare -a ARG_ARRAY + eval "ARG_ARRAY=($DOCKER_ARGS)" + + eval "$(config_export app "$APP" --merged)" + + if [[ -f "$SOURCECODE_WORK_DIR/Procfile" ]]; then + if procfile-util exists --process-type release; then + procfile-util delete --process-type release + fi + fi + + # shellcheck disable=SC2086 + if ! nixpacks build "${DOCKER_BUILD_LABEL_ARGS[@]}" $DOKKU_GLOBAL_BUILD_ARGS "${ARG_ARRAY[@]}" $NIXPACKS_ARGS --name "$IMAGE" "$SOURCECODE_WORK_DIR"; then + dokku_log_warn "Failure building image" + return 1 + fi + + if ! suppress_output "$DOCKER_BIN" image build -f "$PLUGIN_AVAILABLE_PATH/builder-nixpacks/dockerfiles/builder-build.Dockerfile" --build-arg APP_IMAGE="$IMAGE" -t "$IMAGE" "$SOURCECODE_WORK_DIR"; then + dokku_log_warn "Failure injecting docker labels and custom entrypoint on image" + return 1 + fi + + plugn trigger post-build "$BUILDER_TYPE" "$APP" "$SOURCECODE_WORK_DIR" + popd &>/dev/null || pushd "/tmp" >/dev/null +} + +trigger-builder-nixpacks-builder-build "$@" diff --git a/plugins/builder-nixpacks/builder-detect b/plugins/builder-nixpacks/builder-detect new file mode 100755 index 000000000..76800067b --- /dev/null +++ b/plugins/builder-nixpacks/builder-detect @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +source "$PLUGIN_AVAILABLE_PATH/config/functions" +set -eo pipefail +[[ $DOKKU_TRACE ]] && set -x + +trigger-builder-nixpacks-builder-detect() { + declare desc="builder-nixpacks builder-detect plugin trigger" + declare trigger="builder-detect" + declare APP="$1" SOURCECODE_WORK_DIR="$2" + + if [[ -f "$SOURCECODE_WORK_DIR/nixpacks.toml" ]]; then + echo "nixpacks" + return + fi +} + +trigger-builder-nixpacks-builder-detect "$@" diff --git a/plugins/builder-nixpacks/builder-release b/plugins/builder-nixpacks/builder-release new file mode 100755 index 000000000..af79997f7 --- /dev/null +++ b/plugins/builder-nixpacks/builder-release @@ -0,0 +1,31 @@ +#!/usr/bin/env bash +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +set -eo pipefail +[[ $DOKKU_TRACE ]] && set -x + +trigger-builder-nixpacks-builder-release() { + declare desc="builder-nixpacks builder-release plugin trigger" + declare trigger="builder-release" + declare BUILDER_TYPE="$1" APP="$2" IMAGE_TAG="$3" + + if [[ "$BUILDER_TYPE" != "nixpacks" ]]; then + return + fi + + local DOCKER_BUILD_LABEL_ARGS="--label=org.label-schema.schema-version=1.0 --label=org.label-schema.vendor=dokku --label=com.dokku.app-name=$APP --label=com.dokku.image-stage=release --label=dokku" + + plugn trigger pre-release-builder "$BUILDER_TYPE" "$APP" "$IMAGE" + + TMP_WORK_DIR="$(mktemp -d "/tmp/dokku-${DOKKU_PID}-${FUNCNAME[0]}.XXXXXX")" + trap "rm -rf '$TMP_WORK_DIR' >/dev/null" RETURN INT TERM EXIT + + local IMAGE=$(get_app_image_name "$APP" "$IMAGE_TAG") + if ! suppress_output "$DOCKER_BIN" image build "${DOCKER_BUILD_LABEL_ARGS[@]}" $DOKKU_GLOBAL_BUILD_ARGS -f "$PLUGIN_AVAILABLE_PATH/builder-nixpacks/dockerfiles/builder-release.Dockerfile" --build-arg APP_IMAGE="$IMAGE" -t "$IMAGE" "$TMP_WORK_DIR"; then + dokku_log_warn "Failure injecting docker labels on image" + return 1 + fi + + plugn trigger post-release-builder "$BUILDER_TYPE" "$APP" "$IMAGE" +} + +trigger-builder-nixpacks-builder-release "$@" diff --git a/plugins/builder-nixpacks/commands b/plugins/builder-nixpacks/commands new file mode 100755 index 000000000..387e8742a --- /dev/null +++ b/plugins/builder-nixpacks/commands @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -eo pipefail +[[ $DOKKU_TRACE ]] && set -x +source "$PLUGIN_AVAILABLE_PATH/builder-nixpacks/help-functions" + +case "$1" in + help | builder-nixpacks:help) + cmd-builder-nixpacks-help "$@" + ;; + + *) + exit "$DOKKU_NOT_IMPLEMENTED_EXIT" + ;; + +esac diff --git a/plugins/builder-nixpacks/core-post-extract b/plugins/builder-nixpacks/core-post-extract new file mode 100755 index 000000000..eaaa5dd5e --- /dev/null +++ b/plugins/builder-nixpacks/core-post-extract @@ -0,0 +1,30 @@ +#!/usr/bin/env bash +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_AVAILABLE_PATH/builder-nixpacks/internal-functions" +set -eo pipefail +[[ $DOKKU_TRACE ]] && set -x + +trigger-builder-nixpacks-core-post-extract() { + declare desc="builder-nixpacks post-extract plugin trigger" + declare trigger="post-extract" + declare APP="$1" SOURCECODE_WORK_DIR="$2" + local NEW_NIXPACKS_YML="$(fn-builder-nixpacks-computed-nixpackstoml-path "$APP")" + + pushd "$TMP_WORK_DIR" >/dev/null + + if [[ -z "$NEW_NIXPACKS_YML" ]]; then + return + fi + + if [[ ! -f "$NEW_NIXPACKS_YML" ]]; then + rm -f nixpacks.toml + return + fi + + if [[ "$NEW_NIXPACKS_YML" != "nixpacks.toml" ]]; then + mv "$NEW_NIXPACKS_YML" nixpacks.toml + fi + popd &>/dev/null || pushd "/tmp" >/dev/null +} + +trigger-builder-nixpacks-core-post-extract "$@" diff --git a/plugins/builder-nixpacks/dockerfiles/builder-build.Dockerfile b/plugins/builder-nixpacks/dockerfiles/builder-build.Dockerfile new file mode 100644 index 000000000..57aa80d1c --- /dev/null +++ b/plugins/builder-nixpacks/dockerfiles/builder-build.Dockerfile @@ -0,0 +1,7 @@ +ARG APP_IMAGE +FROM $APP_IMAGE + +RUN printf '#!/usr/bin/env bash\nexec bash -l -c -- \"$*\"\n' > /usr/local/bin/entrypoint && \ + chmod +x /usr/local/bin/entrypoint + +ENTRYPOINT ["/usr/local/bin/entrypoint"] diff --git a/plugins/builder-nixpacks/dockerfiles/builder-release.Dockerfile b/plugins/builder-nixpacks/dockerfiles/builder-release.Dockerfile new file mode 100644 index 000000000..cca256f21 --- /dev/null +++ b/plugins/builder-nixpacks/dockerfiles/builder-release.Dockerfile @@ -0,0 +1,2 @@ +ARG APP_IMAGE +FROM $APP_IMAGE diff --git a/plugins/builder-nixpacks/help-functions b/plugins/builder-nixpacks/help-functions new file mode 100755 index 000000000..6426ea29c --- /dev/null +++ b/plugins/builder-nixpacks/help-functions @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +set -eo pipefail +[[ $DOKKU_TRACE ]] && set -x + +cmd-builder-nixpacks-help() { + declare desc="help command" + declare CMD="$1" + local plugin_name="builder-nixpacks" + local plugin_description="Manage the nixpacks builder integration for an app" + + if [[ "$CMD" == "${plugin_name}:help" ]]; then + echo -e "Usage: dokku ${plugin_name}[:COMMAND]" + echo '' + echo "$plugin_description" + echo '' + echo 'Additional commands:' + fn-help-content | sort | column -c2 -t -s, + elif [[ $(ps -o command= $PPID) == *"--all"* ]]; then + fn-help-content + else + cat <] [], Displays a builder-nixpacks report for one or more apps + builder-nixpacks:set (), Set or clear a builder-nixpacks property for an app +help_content +} diff --git a/plugins/builder-nixpacks/install b/plugins/builder-nixpacks/install new file mode 100755 index 000000000..41bc00ab9 --- /dev/null +++ b/plugins/builder-nixpacks/install @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +source "$PLUGIN_CORE_AVAILABLE_PATH/common/property-functions" +set -eo pipefail +[[ $DOKKU_TRACE ]] && set -x + +trigger-builder-nixpacks-install() { + declare desc="installs the builder-nixpacks plugin" + declare trigger="install" + + fn-plugin-property-setup "builder-nixpacks" + + mkdir -p "${DOKKU_LIB_ROOT}/data/builder-nixpacks" + chown -R "${DOKKU_SYSTEM_USER}:${DOKKU_SYSTEM_GROUP}" "${DOKKU_LIB_ROOT}/data/builder-nixpacks" +} + +trigger-builder-nixpacks-install "$@" diff --git a/plugins/builder-nixpacks/internal-functions b/plugins/builder-nixpacks/internal-functions new file mode 100755 index 000000000..582fc33fa --- /dev/null +++ b/plugins/builder-nixpacks/internal-functions @@ -0,0 +1,116 @@ +#!/usr/bin/env bash +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_CORE_AVAILABLE_PATH/common/property-functions" +set -eo pipefail +[[ $DOKKU_TRACE ]] && set -x + +cmd-builder-nixpacks-report() { + declare desc="displays a builder-nixpacks report for one or more apps" + declare cmd="builder-nixpacks:report" + [[ "$1" == "$cmd" ]] && shift 1 + declare APP="$1" INFO_FLAG="$2" + + if [[ -n "$APP" ]] && [[ "$APP" == --* ]]; then + INFO_FLAG="$APP" + APP="" + fi + + if [[ -z "$APP" ]] && [[ -z "$INFO_FLAG" ]]; then + INFO_FLAG="true" + fi + + if [[ -z "$APP" ]]; then + for app in $(dokku_apps); do + cmd-builder-nixpacks-report-single "$app" "$INFO_FLAG" | tee || true + done + else + cmd-builder-nixpacks-report-single "$APP" "$INFO_FLAG" + fi +} + +cmd-builder-nixpacks-report-single() { + declare APP="$1" INFO_FLAG="$2" + if [[ "$INFO_FLAG" == "true" ]]; then + INFO_FLAG="" + fi + verify_app_name "$APP" + local flag_map=( + "--builder-nixpacks-computed-nixpackstoml-path: $(fn-builder-nixpacks-computed-nixpackstoml-path "$APP")" + "--builder-nixpacks-global-nixpackstoml-path: $(fn-builder-nixpacks-global-nixpackstoml-path "$APP")" + "--builder-nixpacks-nixpackstoml-path: $(fn-builder-nixpacks-nixpackstoml-path "$APP")" + "--builder-nixpacks-computed-no-cache: $(fn-builder-nixpacks-computed-no-cache "$APP")" + "--builder-nixpacks-global-no-cache: $(fn-builder-nixpacks-global-no-cache "$APP")" + "--builder-nixpacks-no-cache: $(fn-builder-nixpacks-no-cache "$APP")" + ) + + if [[ -z "$INFO_FLAG" ]]; then + dokku_log_info2_quiet "${APP} builder-nixpacks information" + for flag in "${flag_map[@]}"; do + key="$(echo "${flag#--}" | cut -f1 -d' ' | tr - ' ')" + dokku_log_verbose "$(printf "%-30s %-25s" "${key^}" "${flag#*: }")" + done + else + local match=false + local value_exists=false + for flag in "${flag_map[@]}"; do + valid_flags="${valid_flags} $(echo "$flag" | cut -d':' -f1)" + if [[ "$flag" == "${INFO_FLAG}:"* ]]; then + value=${flag#*: } + size="${#value}" + if [[ "$size" -ne 0 ]]; then + echo "$value" && match=true && value_exists=true + else + match=true + fi + fi + done + [[ "$match" == "true" ]] || dokku_log_fail "Invalid flag passed, valid flags:${valid_flags}" + [[ "$value_exists" == "true" ]] || dokku_log_fail "not deployed" + fi +} + +fn-builder-nixpacks-computed-nixpackstoml-path() { + declare APP="$1" + + file="$(fn-builder-nixpacks-nixpackstoml-path "$APP")" + if [[ "$file" == "" ]]; then + file="$(fn-builder-nixpacks-global-nixpackstoml-path "$APP")" + fi + + echo "$file" +} + +fn-builder-nixpacks-global-nixpackstoml-path() { + declare APP="$1" + + fn-plugin-property-get "builder-nixpacks" "--global" "nixpackstoml-path" "nixpacks.toml" +} + +fn-builder-nixpacks-nixpackstoml-path() { + declare APP="$1" + + fn-plugin-property-get "builder-nixpacks" "$APP" "nixpackstoml-path" "" +} + +fn-builder-nixpacks-computed-no-cache() { + declare APP="$1" + + file="$(fn-builder-nixpacks-no-cache "$APP")" + if [[ "$file" == "" ]]; then + file="$(fn-builder-nixpacks-global-no-cache "$APP")" + fi + + echo "$file" +} + +fn-builder-nixpacks-global-no-cache() { + declare APP="$1" + + fn-plugin-property-get "builder-nixpacks" "--global" "no-cache" "false" +} + +fn-builder-nixpacks-no-cache() { + declare APP="$1" + + fn-plugin-property-get "builder-nixpacks" "$APP" "no-cache" "" +} diff --git a/plugins/builder-nixpacks/plugin.toml b/plugins/builder-nixpacks/plugin.toml new file mode 100644 index 000000000..1a7356ea9 --- /dev/null +++ b/plugins/builder-nixpacks/plugin.toml @@ -0,0 +1,4 @@ +[plugin] +description = "dokku core builder-nixpacks plugin" +version = "0.31.4" +[plugin.config] diff --git a/plugins/builder-nixpacks/post-app-clone-setup b/plugins/builder-nixpacks/post-app-clone-setup new file mode 100755 index 000000000..95541bc1c --- /dev/null +++ b/plugins/builder-nixpacks/post-app-clone-setup @@ -0,0 +1,14 @@ +#!/usr/bin/env bash +source "$PLUGIN_CORE_AVAILABLE_PATH/common/property-functions" +set -eo pipefail +[[ $DOKKU_TRACE ]] && set -x + +trigger-builder-nixpacks-post-app-clone-setup() { + declare desc="sets up properties for new app" + declare trigger="post-app-clone-setup" + declare OLD_APP="$1" NEW_APP="$2" + + fn-plugin-property-clone "builder-nixpacks" "$OLD_APP" "$NEW_APP" +} + +trigger-builder-nixpacks-post-app-clone-setup "$@" diff --git a/plugins/builder-nixpacks/post-app-rename-setup b/plugins/builder-nixpacks/post-app-rename-setup new file mode 100755 index 000000000..00ea04aa1 --- /dev/null +++ b/plugins/builder-nixpacks/post-app-rename-setup @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +source "$PLUGIN_CORE_AVAILABLE_PATH/common/property-functions" +set -eo pipefail +[[ $DOKKU_TRACE ]] && set -x + +trigger-builder-nixpacks-post-app-rename-setup() { + declare desc="updates settings for new app" + declare trigger="post-app-rename-setup" + declare OLD_APP="$1" NEW_APP="$2" + + fn-plugin-property-clone "builder-nixpacks" "$OLD_APP" "$NEW_APP" + fn-plugin-property-destroy "builder-nixpacks" "$OLD_APP" +} + +trigger-builder-nixpacks-post-app-rename-setup "$@" diff --git a/plugins/builder-nixpacks/post-delete b/plugins/builder-nixpacks/post-delete new file mode 100755 index 000000000..aedb082cd --- /dev/null +++ b/plugins/builder-nixpacks/post-delete @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +source "$PLUGIN_CORE_AVAILABLE_PATH/common/property-functions" +set -eo pipefail +[[ $DOKKU_TRACE ]] && set -x + +trigger-builder-nixpacks-post-delete() { + declare desc="destroys the builder-nixpacks properties for a given app" + declare trigger="post-delete" + declare APP="$1" + + fn-plugin-property-destroy "builder-nixpacks" "$APP" + rm -rf "${DOKKU_LIB_ROOT}/data/builder-nixpacks/$APP" +} + +trigger-builder-nixpacks-post-delete "$@" diff --git a/plugins/builder-nixpacks/report b/plugins/builder-nixpacks/report new file mode 100755 index 000000000..727356552 --- /dev/null +++ b/plugins/builder-nixpacks/report @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +source "$PLUGIN_AVAILABLE_PATH/builder-nixpacks/internal-functions" +set -eo pipefail +[[ $DOKKU_TRACE ]] && set -x + +cmd-builder-nixpacks-report-single "$@" diff --git a/plugins/builder-nixpacks/subcommands/default b/plugins/builder-nixpacks/subcommands/default new file mode 100755 index 000000000..9c72c5c46 --- /dev/null +++ b/plugins/builder-nixpacks/subcommands/default @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +source "$PLUGIN_AVAILABLE_PATH/builder-nixpacks/help-functions" +set -eo pipefail +[[ $DOKKU_TRACE ]] && set -x + +cmd-builder-nixpacks-help "builder-nixpacks:help" diff --git a/plugins/builder-nixpacks/subcommands/report b/plugins/builder-nixpacks/subcommands/report new file mode 100755 index 000000000..4ea4b1d13 --- /dev/null +++ b/plugins/builder-nixpacks/subcommands/report @@ -0,0 +1,6 @@ +#!/usr/bin/env bash +source "$PLUGIN_AVAILABLE_PATH/builder-nixpacks/internal-functions" +set -eo pipefail +[[ $DOKKU_TRACE ]] && set -x + +cmd-builder-nixpacks-report "$@" diff --git a/plugins/builder-nixpacks/subcommands/set b/plugins/builder-nixpacks/subcommands/set new file mode 100755 index 000000000..711b60d72 --- /dev/null +++ b/plugins/builder-nixpacks/subcommands/set @@ -0,0 +1,30 @@ +#!/usr/bin/env bash +source "$PLUGIN_CORE_AVAILABLE_PATH/common/functions" +source "$PLUGIN_CORE_AVAILABLE_PATH/common/property-functions" +set -eo pipefail +[[ $DOKKU_TRACE ]] && set -x + +cmd-builder-nixpacks-set() { + declare desc="set or clear a builder-nixpacks property for an app" + declare cmd="builder-nixpacks:set" + [[ "$1" == "$cmd" ]] && shift 1 + declare APP="$1" KEY="$2" VALUE="$3" + local VALID_KEYS=("nixpackstoml-path" "no-cache") + [[ "$APP" == "--global" ]] || verify_app_name "$APP" + + [[ -z "$KEY" ]] && dokku_log_fail "No key specified" + + if ! fn-in-array "$KEY" "${VALID_KEYS[@]}"; then + dokku_log_fail "Invalid key specified, valid keys include: nixpackstoml-path, no-cache" + fi + + if [[ -n "$VALUE" ]]; then + dokku_log_info2_quiet "Setting ${KEY} to ${VALUE}" + fn-plugin-property-write "builder-nixpacks" "$APP" "$KEY" "$VALUE" + else + dokku_log_info2_quiet "Unsetting ${KEY}" + fn-plugin-property-delete "builder-nixpacks" "$APP" "$KEY" + fi +} + +cmd-builder-nixpacks-set "$@" diff --git a/tests/unit/builder-nixpacks.bats b/tests/unit/builder-nixpacks.bats new file mode 100644 index 000000000..39285c183 --- /dev/null +++ b/tests/unit/builder-nixpacks.bats @@ -0,0 +1,52 @@ +#!/usr/bin/env bats + +load test_helper + +setup_file() { + install_nixpacks +} + +setup() { + create_app +} + +teardown() { + destroy_app +} + +@test "(builder-nixpacks:set)" { + run /bin/bash -c "dokku config:set $TEST_APP SECRET_KEY=fjdkslafjdk" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku builder:set $TEST_APP selected nixpacks" + echo "output: $output" + echo "status: $status" + assert_success + + run deploy_app python dokku@dokku.me:$TEST_APP inject_requirements_txt + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains 'load build definition from Dockerfile' + assert_output_contains "SECRET_KEY: fjdkslafjdk" + + run /bin/bash -c "dokku builder-nixpacks:set $TEST_APP nixpackstoml-path nonexistent.toml" + echo "output: $output" + echo "status: $status" + assert_success + + run /bin/bash -c "dokku ps:rebuild $TEST_APP" + echo "output: $output" + echo "status: $status" + assert_success + assert_output_contains 'load build definition from Dockerfile' +} + +inject_requirements_txt() { + local APP="$1" + local APP_REPO_DIR="$2" + [[ -z "$APP" ]] && local APP="$TEST_APP" + echo "flask" >>"$APP_REPO_DIR/requirements.txt" +} diff --git a/tests/unit/test_helper.bash b/tests/unit/test_helper.bash index 536656728..0ea1a45ed 100644 --- a/tests/unit/test_helper.bash +++ b/tests/unit/test_helper.bash @@ -601,6 +601,13 @@ detach_delete_network() { delete_network "$NETWORK_NAME" } +convert_to_dockerfile() { + local APP="$1" + local APP_REPO_DIR="$2" + [[ -z "$APP" ]] && local APP="$TEST_APP" + mv "$APP_REPO_DIR/dockerfile.Dockerfile" "$APP_REPO_DIR/Dockerfile" +} + install_pack() { if ! command -v "pack" &>/dev/null; then add-apt-repository --yes ppa:cncf-buildpacks/pack-cli @@ -609,9 +616,8 @@ install_pack() { fi } -convert_to_dockerfile() { - local APP="$1" - local APP_REPO_DIR="$2" - [[ -z "$APP" ]] && local APP="$TEST_APP" - mv "$APP_REPO_DIR/dockerfile.Dockerfile" "$APP_REPO_DIR/Dockerfile" +install_nixpacks() { + if ! command -v "nixpacks" &>/dev/null; then + curl -sSL https://nixpacks.com/install.sh | FORCE=1 bash + fi }