Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .github/CODEOWNERS

This file was deleted.

10 changes: 10 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "monthly"
labels:
- "dependencies"
- "github actions"
- "skip changelog"
2 changes: 1 addition & 1 deletion .github/workflows/check_changelog.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
if: (!contains(github.event.pull_request.labels.*.name, 'skip changelog'))
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Check that CHANGELOG is touched
run: |
git fetch origin ${{ github.base_ref }} --depth 1 && \
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ jobs:
options: --user root
strategy:
matrix:
stack_number: ["20", "22", "24"]
stack_number: ["22", "24", "26"]
env:
STACK: heroku-${{ matrix.stack_number }}
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Functional tests on heroku:${{ matrix.stack_number }}-build
run: test/run

Expand All @@ -30,6 +30,6 @@ jobs:
container:
image: koalaman/shellcheck-alpine:v0.9.0
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: shellcheck
run: shellcheck -x bin/compile bin/detect bin/release bin/report
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
.anvil
.DS_Store
.idea
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## Unreleased

## 2025-03-11

- Configures `GIT_EXEC_PATH` if `git` is installed. ([#143](https://github.com/heroku/heroku-buildpack-apt/pull/143))

## 2024-06-24

- The cache is now correctly invalidated if the stack version of an existing cache cannot be determined. ([#133](https://github.com/heroku/heroku-buildpack-apt/pull/133))
Expand Down
12 changes: 6 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
test: heroku-24-build heroku-22-build heroku-20-build
test: heroku-26-build heroku-24-build heroku-22-build

shellcheck:
@shellcheck -x bin/compile bin/detect bin/release bin/report

heroku-26-build:
@echo "Running tests in docker (heroku-26-build)..."
@docker run --user root -v $(shell pwd):/buildpack:ro --rm -it -e "STACK=heroku-26" heroku/heroku:26-build bash -c 'cp -r /buildpack /buildpack_test; cd /buildpack_test/; test/run;'
@echo ""

heroku-24-build:
@echo "Running tests in docker (heroku-24-build)..."
@docker run --user root -v $(shell pwd):/buildpack:ro --rm -it -e "STACK=heroku-24" heroku/heroku:24-build bash -c 'cp -r /buildpack /buildpack_test; cd /buildpack_test/; test/run;'
Expand All @@ -12,8 +17,3 @@ heroku-22-build:
@echo "Running tests in docker (heroku-22-build)..."
@docker run -v $(shell pwd):/buildpack:ro --rm -it -e "STACK=heroku-22" heroku/heroku:22-build bash -c 'cp -r /buildpack /buildpack_test; cd /buildpack_test/; test/run;'
@echo ""

heroku-20-build:
@echo "Running tests in docker (heroku-20-build)..."
@docker run -v $(shell pwd):/buildpack:ro --rm -it -e "STACK=heroku-20" heroku/heroku:20-build bash -c 'cp -r /buildpack /buildpack_test; cd /buildpack_test/; test/run;'
@echo ""
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ Add support for apt-based dependencies during both compile and runtime.

Added ability to also specify custom repositories through **:repo:** in `Aptfile` (see example below).

> [!Important]
> This buildpack is compatible with Heroku's [Cedar generation platform](https://devcenter.heroku.com/articles/generations#cedar) only.
>
> For equivalent functionality on Heroku's [Fir generation platform](https://devcenter.heroku.com/articles/generations#fir),
> then check out the `.deb` Packages CNB [here](https://github.com/heroku/buildpacks-deb-packages).

## Usage

This buildpack is not meant to be used on its own, and instead should be in used in combination with Heroku's [multiple buildpack support](https://devcenter.heroku.com/articles/using-multiple-buildpacks-for-an-app).
Expand Down
28 changes: 24 additions & 4 deletions bin/compile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#!/usr/bin/env bash
# bin/compile <build-dir> <cache-dir>
# bin/compile <build-dir> <cache-dir> <env-dir>

# fail fast
set -eo pipefail
Expand All @@ -10,7 +10,7 @@ set -eo pipefail
# parse and derive params
BUILD_DIR=$1
CACHE_DIR=$2
LP_DIR=$(cd "$(dirname "$0")"; cd ..; pwd)
BP_DIR=$(cd "$(dirname "$0")"; cd ..; pwd)

function error() {
echo " ! $*" >&2
Expand Down Expand Up @@ -138,7 +138,8 @@ done < <(grep -s -e '^blackhole ' "$BUILD_DIR"/Aptfile)

topic "Writing profile script"
mkdir -p "$BUILD_DIR/.profile.d"
cat <<EOF >"$BUILD_DIR/.profile.d/000_apt.sh"
RUNTIME_PROFILE_SCRIPT="$BUILD_DIR/.profile.d/000_apt.sh"
cat <<EOF >"$RUNTIME_PROFILE_SCRIPT"
export PATH="\$HOME/.apt/usr/bin:\$PATH"
export LD_LIBRARY_PATH="\$HOME/.apt/usr/lib/x86_64-linux-gnu:\$HOME/.apt/usr/lib/i386-linux-gnu:\$HOME/.apt/usr/lib:\$LD_LIBRARY_PATH"
export LIBRARY_PATH="\$HOME/.apt/usr/lib/x86_64-linux-gnu:\$HOME/.apt/usr/lib/i386-linux-gnu:\$HOME/.apt/usr/lib:\$LIBRARY_PATH"
Expand All @@ -157,7 +158,26 @@ export CPPPATH="$INCLUDE_PATH"
export PKG_CONFIG_PATH="$BUILD_DIR/.apt/usr/lib/x86_64-linux-gnu/pkgconfig:$BUILD_DIR/.apt/usr/lib/i386-linux-gnu/pkgconfig:$BUILD_DIR/.apt/usr/lib/pkgconfig:$PKG_CONFIG_PATH"

#give environment to later buildpacks
export | grep -E -e ' (PATH|LD_LIBRARY_PATH|LIBRARY_PATH|INCLUDE_PATH|CPATH|CPPPATH|PKG_CONFIG_PATH)=' > "$LP_DIR/export"
topic "Exporting environment"
BUILDPACK_EXPORT_FILE="$BP_DIR/export"
export | grep -E -e ' (PATH|LD_LIBRARY_PATH|LIBRARY_PATH|INCLUDE_PATH|CPATH|CPPPATH|PKG_CONFIG_PATH)=' > "$BUILDPACK_EXPORT_FILE"

topic "Rewrite package-config files"
find "$BUILD_DIR/.apt" -type f -ipath '*/pkgconfig/*.pc' -print0 | xargs -0 --no-run-if-empty -n 1 sed -i -e 's!^prefix=\(.*\)$!prefix='"$BUILD_DIR"'/.apt\1!g'

# post-installation logic for git
# If git was installed by this buildpack set `GIT_EXEC_PATH` to work around:
# https://github.com/heroku/heroku-buildpack-apt/issues/137
if [[ -f "${BUILD_DIR}/.apt/usr/bin/git" ]]; then
GIT_CORE_DIR="${BUILD_DIR}/.apt/usr/lib/git-core"
if [[ -d "$GIT_CORE_DIR" ]]; then
topic "Setting GIT_EXEC_PATH to $GIT_CORE_DIR"
# set env var in runtime profile script
# shellcheck disable=SC2016
echo 'export GIT_EXEC_PATH="$HOME/.apt/usr/lib/git-core"' >> "$RUNTIME_PROFILE_SCRIPT"
# export the env var to later buildpacks
echo "declare -x GIT_EXEC_PATH=\"$GIT_CORE_DIR\"" >> "$BUILDPACK_EXPORT_FILE"
else
topic "Git core directory $GIT_CORE_DIR is either missing or empty. Skipping GIT_EXEC_PATH setup."
fi
fi
1 change: 0 additions & 1 deletion test/fixtures/custom-package-url-heroku-20/Aptfile

This file was deleted.

2 changes: 2 additions & 0 deletions test/fixtures/custom-package-url-heroku-26/Aptfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# no resolute package for wkhtmltopdf yet, so using jammy package
https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6.1-2/wkhtmltox_0.12.6.1-2.jammy_amd64.deb
2 changes: 0 additions & 2 deletions test/fixtures/custom-repository-heroku-20/Aptfile

This file was deleted.

2 changes: 1 addition & 1 deletion test/fixtures/custom-repository-heroku-22/Aptfile
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
:repo:deb http://us.archive.ubuntu.com/ubuntu/ jammy multiverse
fasttracker2
translate-shell
2 changes: 1 addition & 1 deletion test/fixtures/custom-repository-heroku-24/Aptfile
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
:repo:deb http://us.archive.ubuntu.com/ubuntu/ noble multiverse
fasttracker2
translate-shell
2 changes: 2 additions & 0 deletions test/fixtures/custom-repository-heroku-26/Aptfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
:repo:deb http://us.archive.ubuntu.com/ubuntu/ resolute multiverse
translate-shell
1 change: 1 addition & 0 deletions test/fixtures/git/Aptfile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
git
114 changes: 91 additions & 23 deletions test/run
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
#!/usr/bin/env bash

testCompilePackageNames() {
compile "package-names"
bp_dir=$(mktmpdir)
build_dir=$(mktmpdir)
cache_dir=$(mktmpdir)
compile "package-names" "${bp_dir}" "${build_dir}" "${cache_dir}"

assertCaptured "Updating APT package index"
assertCaptured "Fetching .debs for xmlsec1"
assertCaptured "Fetching .debs for s3cmd wget"
Expand All @@ -14,30 +18,50 @@ testCompilePackageNames() {
assertCaptured "Writing profile script"
assertCaptured "Rewrite package-config files"
assertCapturedSuccess

assertProfileContains 'export PATH="$HOME/.apt/usr/bin:$PATH"' "$build_dir"
assertProfileContains 'export LD_LIBRARY_PATH="$HOME/.apt/usr/lib/x86_64-linux-gnu:$HOME/.apt/usr/lib/i386-linux-gnu:$HOME/.apt/usr/lib:$LD_LIBRARY_PATH"' "$build_dir"
assertProfileContains 'export LIBRARY_PATH="$HOME/.apt/usr/lib/x86_64-linux-gnu:$HOME/.apt/usr/lib/i386-linux-gnu:$HOME/.apt/usr/lib:$LIBRARY_PATH"' "$build_dir"
assertProfileContains 'export INCLUDE_PATH="$HOME/.apt/usr/include:$HOME/.apt/usr/include/x86_64-linux-gnu:$INCLUDE_PATH"' "$build_dir"
assertProfileContains 'export CPATH="$INCLUDE_PATH"' "$build_dir"
assertProfileContains 'export CPPPATH="$INCLUDE_PATH"' "$build_dir"
assertProfileContains 'export PKG_CONFIG_PATH="$HOME/.apt/usr/lib/x86_64-linux-gnu/pkgconfig:$HOME/.apt/usr/lib/i386-linux-gnu/pkgconfig:$HOME/.apt/usr/lib/pkgconfig:$PKG_CONFIG_PATH"' "$build_dir"
assertProfileNotContains 'export GIT_EXEC_PATH="$HOME/.apt/usr/lib/git-core"' "$build_dir"

assertExportContains "declare -x PATH=\"$build_dir/.apt/usr/bin:" "$bp_dir"
assertExportContains "declare -x LD_LIBRARY_PATH=\"$build_dir/.apt/usr/lib/x86_64-linux-gnu:$build_dir/.apt/usr/lib/i386-linux-gnu:$build_dir/.apt/usr/lib:\"" "$bp_dir"
assertExportContains "declare -x LIBRARY_PATH=\"$build_dir/.apt/usr/lib/x86_64-linux-gnu:$build_dir/.apt/usr/lib/i386-linux-gnu:$build_dir/.apt/usr/lib:\"" "$bp_dir"
assertExportContains "declare -x INCLUDE_PATH=\"$build_dir/.apt/usr/include:$build_dir/.apt/usr/include/x86_64-linux-gnu:\"" "$bp_dir"
assertExportContains "declare -x CPATH=\"$build_dir/.apt/usr/include:$build_dir/.apt/usr/include/x86_64-linux-gnu:\"" "$bp_dir"
assertExportContains "declare -x CPPPATH=\"$build_dir/.apt/usr/include:$build_dir/.apt/usr/include/x86_64-linux-gnu:\"" "$bp_dir"
assertExportContains "declare -x PKG_CONFIG_PATH=\"$build_dir/.apt/usr/lib/x86_64-linux-gnu/pkgconfig:$build_dir/.apt/usr/lib/i386-linux-gnu/pkgconfig:$build_dir/.apt/usr/lib/pkgconfig:\"" "$bp_dir"
assertExportNotContains "declare -x GIT_EXEC_PATH=\"$build_dir/.apt/usr/lib/git-core\"" "$bp_dir"
}

testCacheInvalidation() {
bp_dir=$(mktmpdir)
build_dir=$(mktmpdir)
cache_dir=$(mktmpdir)

# Cold cache
compile "package-names" "${cache_dir}"
compile "package-names" "${bp_dir}" "${build_dir}" "${cache_dir}"
assertCaptured "Detected Aptfile or Stack changes, flushing cache"
assertCapturedSuccess

# Warm cache
compile "package-names" "${cache_dir}"
compile "package-names" "${bp_dir}" "${build_dir}" "${cache_dir}"
assertCaptured "Reusing cache"
assertCapturedSuccess

# Cache invalidated on stack change
echo 'some-old-stack' > "${cache_dir}/.apt/STACK"
compile "package-names" "${cache_dir}"
compile "package-names" "${bp_dir}" "${build_dir}" "${cache_dir}"
assertCaptured "Detected Aptfile or Stack changes, flushing cache"
assertCapturedSuccess

# Cache invalidated if stack version file missing (eg cache from old buildpack version)
rm "${cache_dir}/.apt/STACK"
compile "package-names" "${cache_dir}"
compile "package-names" "${bp_dir}" "${build_dir}" "${cache_dir}"
assertCaptured "Detected Aptfile or Stack changes, flushing cache"
assertCapturedSuccess
}
Expand All @@ -52,10 +76,11 @@ testReportPackageNames() {

testCompileCustomPackageUrl() {
declare -A download_urls=(
[heroku-20]="https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6-1/wkhtmltox_0.12.6-1.focal_amd64.deb"
[heroku-22]="https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6.1-2/wkhtmltox_0.12.6.1-2.jammy_amd64.deb"
# no noble package for wkhtmltopdf yet, so using jammy package
[heroku-24]="https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6.1-2/wkhtmltox_0.12.6.1-2.jammy_amd64.deb"
# no resolute package for wkhtmltopdf yet, so using jammy package
[heroku-26]="https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6.1-2/wkhtmltox_0.12.6.1-2.jammy_amd64.deb"
)
compile "custom-package-url-$STACK"
assertCaptured "Updating APT package index"
Expand All @@ -68,10 +93,11 @@ testCompileCustomPackageUrl() {

testReportCustomPackageUrl() {
declare -A download_urls=(
[heroku-20]="https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6-1/wkhtmltox_0.12.6-1.focal_amd64.deb"
[heroku-22]="https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6.1-2/wkhtmltox_0.12.6.1-2.jammy_amd64.deb"
# no noble package for wkhtmltopdf yet, so using jammy package
[heroku-24]="https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6.1-2/wkhtmltox_0.12.6.1-2.jammy_amd64.deb"
# no resolute package for wkhtmltopdf yet, so using jammy package
[heroku-26]="https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6.1-2/wkhtmltox_0.12.6.1-2.jammy_amd64.deb"
)
report "custom-package-url-$STACK"
assertNotCaptured "^packages"
Expand All @@ -82,29 +108,30 @@ testReportCustomPackageUrl() {

testCompileCustomRepository() {
declare -A ubuntu_release_names=(
[heroku-20]="focal"
[heroku-22]="jammy"
[heroku-24]="noble"
[heroku-26]="resolute"
)
arch="$(dpkg --print-architecture)"
compile "custom-repository-$STACK"
assertCaptured "Adding custom repositories"
assertCaptured "Updating APT package index"
assertCaptured "http://us.archive.ubuntu.com/ubuntu ${ubuntu_release_names[$STACK]}/multiverse amd64 Packages"
assertCaptured "Fetching .debs for fasttracker2"
assertCaptured "Installing fasttracker2"
assertCaptured "http://us.archive.ubuntu.com/ubuntu ${ubuntu_release_names[$STACK]}/multiverse ${arch} Packages"
assertCaptured "Fetching .debs for translate-shell"
assertCaptured "Installing translate-shell"
assertCaptured "Writing profile script"
assertCaptured "Rewrite package-config files"
assertCapturedSuccess
}

testReportCustomRepository() {
declare -A ubuntu_release_names=(
[heroku-20]="focal"
[heroku-22]="jammy"
[heroku-24]="noble"
[heroku-26]="resolute"
)
report "custom-repository-$STACK"
assertCaptured "packages: \"fasttracker2\""
assertCaptured "packages: \"translate-shell\""
assertNotCaptured "custom_packages"
assertCaptured "custom_repositories: \"deb http://us.archive.ubuntu.com/ubuntu/ ${ubuntu_release_names[$STACK]} multiverse\""
assertCapturedSuccess
Expand Down Expand Up @@ -155,29 +182,46 @@ testReportCustomRepositoryNoPackages() {
assertCapturedSuccess
}

testGitEnvConfig() {
bp_dir=$(mktmpdir)
build_dir=$(mktmpdir)
compile "git" "${bp_dir}" "${build_dir}"

assertCaptured "Setting GIT_EXEC_PATH"
assertCapturedSuccess

assertProfileContains 'export GIT_EXEC_PATH="$HOME/.apt/usr/lib/git-core"' "$build_dir"

assertExportContains "declare -x GIT_EXEC_PATH=\"$build_dir/.apt/usr/lib/git-core\"" "$bp_dir"
}

pushd "$(dirname 0)" >/dev/null || exit 1
popd >/dev/null || exit 1

source "$(pwd)"/test/utils

compile() {
default_process_types_cleanup
bp_dir=$(mktmpdir)
compile_dir=$(mktmpdir)
fixture="$1"
bp_dir=${2:-$(mktmpdir)}
build_dir=${3:-$(mktmpdir)}
cache_dir=${4:-$(mktmpdir)}
env_dir=$(mktmpdir)
cp -a "$(pwd)"/* "${bp_dir}"
cp -a "${bp_dir}"/test/fixtures/"$1"/. "${compile_dir}"
capture "${bp_dir}"/bin/compile "${compile_dir}" "${2:-$(mktmpdir)}" "$3"
cp -a "${bp_dir}"/test/fixtures/"$fixture"/. "${build_dir}"
capture "${bp_dir}"/bin/compile "${build_dir}" "${cache_dir}" "${env_dir}"
}

report() {
default_process_types_cleanup
compile_dir=${1:-$(mktmpdir)}
cache_dir=${2:-$(mktmpdir)}
env_dir=${3:-$(mktmpdir)}
bp_dir=$(mktmpdir)
fixture="$1"
bp_dir=${2:-$(mktmpdir)}
build_dir=${3:-$(mktmpdir)}
cache_dir=${4:-$(mktmpdir)}
env_dir=$(mktmpdir)
cp -a "$(pwd)"/* "${bp_dir}"
cp -a "${bp_dir}"/test/fixtures/"$1"/. "${compile_dir}"
capture "${bp_dir}"/bin/report "${compile_dir}" "${cache_dir}" "${env_dir}"
cp -a "${bp_dir}"/test/fixtures/"$fixture"/. "${build_dir}"
capture "${bp_dir}"/bin/report "${build_dir}" "${cache_dir}" "${env_dir}"
}

mktmpdir() {
Expand All @@ -194,4 +238,28 @@ default_process_types_cleanup() {
fi
}

assertProfileContains() {
text="$1"
build_dir="$2"
assertFileContains "$text" "$build_dir/.profile.d/000_apt.sh"
}

assertProfileNotContains() {
text="$1"
build_dir="$2"
assertFileNotContains "$text" "$build_dir/.profile.d/000_apt.sh"
}

assertExportContains() {
text="$1"
bp_dir="$2"
assertFileContains "$text" "$bp_dir/export"
}

assertExportNotContains() {
text="$1"
bp_dir="$2"
assertFileNotContains "$text" "$bp_dir/export"
}

source "$(pwd)"/test/shunit2