diff --git a/README.md b/README.md index 618dd6a..9ddae5d 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ steps: - label: ':nodejs: Install dependencies' command: npm ci plugins: - - cache#v1.1.0: + - cache#v1.3.0: manifest: package-lock.json path: node_modules restore: file @@ -131,7 +131,7 @@ steps: - label: ':nodejs: Install dependencies' command: npm ci plugins: - - cache#v1.1.0: + - cache#v1.3.0: manifest: package-lock.json path: node_modules restore: pipeline @@ -142,7 +142,7 @@ steps: - label: ':test_tube: Run tests' command: npm test # does not save cache, not necessary plugins: - - cache#v1.1.0: + - cache#v1.3.0: manifest: package-lock.json path: node_modules restore: file @@ -151,7 +151,7 @@ steps: if: build.branch == "master" command: npm run deploy plugins: - - cache#v1.1.0: + - cache#v1.3.0: manifest: package-lock.json path: node_modules restore: file diff --git a/hooks/post-checkout b/hooks/post-checkout index 7a88bec..a98fcfb 100755 --- a/hooks/post-checkout +++ b/hooks/post-checkout @@ -1,7 +1,7 @@ #!/bin/bash set -euo pipefail -DIR="$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)" +DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # shellcheck source=lib/shared.bash . "${DIR}/../lib/shared.bash" @@ -10,7 +10,7 @@ DIR="$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)" RESTORE_PATH=$(plugin_read_config PATH) -if [ -z "${RESTORE_PATH}" ] ; then +if [ -z "${RESTORE_PATH}" ]; then echo "+++ 🚨 Missing path option in the cache plugin to restore" exit 1 fi diff --git a/lib/compression.bash b/lib/compression.bash index 824007c..227a33d 100644 --- a/lib/compression.bash +++ b/lib/compression.bash @@ -1,6 +1,6 @@ #!/bin/bash -DIR="$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)" +DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # shellcheck source=lib/plugin.bash . "${DIR}/plugin.bash" @@ -35,17 +35,34 @@ compress() { echo "Compressing ${COMPRESSED_FILE} with ${COMPRESSION}..." if [ "${COMPRESSION}" = 'tgz' ]; then - tar czf "${FILE}" "${COMPRESSED_FILE}" + TAR_OPTS='cz' + if is_absolute_path "${COMPRESSED_FILE}"; then + TAR_OPTS="${TAR_OPTS}"P + fi + + tar "${TAR_OPTS}"f "${FILE}" "${COMPRESSED_FILE}" elif [ "${COMPRESSION}" = 'zip' ]; then - # because ZIP complains if the file does not end with .zip - zip -r "${FILE}.zip" "${COMPRESSED_FILE}" - mv "${FILE}.zip" "${FILE}" + if is_absolute_path "${COMPRESSED_FILE}"; then + local COMPRESS_DIR + COMPRESS_DIR="$(dirname "${COMPRESSED_FILE}")" + ( # subshell to avoid changing the working directory + # shellcheck disable=SC2164 # we will exit anyway + cd "${COMPRESS_DIR}" + # because ZIP complains if the file does not end with .zip + zip -r "${FILE}.zip" "${COMPRESSED_FILE}" + mv "${FILE}.zip" "${FILE}" + ) + else + # because ZIP complains if the file does not end with .zip + zip -r "${FILE}.zip" "${COMPRESSED_FILE}" + mv "${FILE}.zip" "${FILE}" + fi fi } uncompress() { local FILE="$1" - local _RESTORE_PATH="$2" # pretty sure this is not necessary + local RESTORE_PATH="$2" local COMPRESSION='' COMPRESSION="$(plugin_read_config COMPRESSION 'none')" @@ -53,10 +70,33 @@ uncompress() { echo "Cache is compressed, uncompressing with ${COMPRESSION}..." if [ "${COMPRESSION}" = 'tgz' ]; then - tar xzf "${FILE}" + TAR_OPTS='xz' + if is_absolute_path "${RESTORE_PATH}"; then + TAR_OPTS="${TAR_OPTS}"P + fi + + tar "${TAR_OPTS}"f "${FILE}" "${RESTORE_PATH}" elif [ "${COMPRESSION}" = 'zip' ]; then - # because ZIP complains if the file does not end with .zip - mv "${FILE}" "${FILE}.zip" - unzip -o "${FILE}.zip" + if is_absolute_path "${RESTORE_PATH}"; then + local RESTORE_DIR + RESTORE_DIR="$(dirname "${RESTORE_PATH}")" + ( # subshell to avoid changing the working directory + mkdir -p "${RESTORE_DIR}" + # shellcheck disable=SC2164 # we will exit anyway + cd "${RESTORE_DIR}" + mv "${FILE}" "${RESTORE_DIR}/compressed.zip" + unzip -o "compressed.zip" + rm "compressed.zip" + ) + else + # because ZIP complains if the file does not end with .zip + mv "${FILE}" "${FILE}.zip" + unzip -o "${FILE}.zip" + fi fi } + +is_absolute_path() { + local FILEPATH="${1}" + [ "${FILEPATH:0:1}" = "/" ] +} diff --git a/tests/post-checkout-tgz.bats b/tests/post-checkout-tgz.bats index d51f37c..7de9537 100644 --- a/tests/post-checkout-tgz.bats +++ b/tests/post-checkout-tgz.bats @@ -24,7 +24,8 @@ setup() { # stub is the same for all tests stub tar \ - "xzf \* \* : echo uncompressed \$2 into \$3" + "\* \* \* : echo uncompressed \$2 into \$3 with options \$1" + } teardown() { @@ -45,6 +46,7 @@ teardown() { assert_success assert_output --partial 'Cache hit at file level' assert_output --partial 'Cache is compressed, uncompressing with tgz' + assert_output --partial "with options xzf" unstub cache_dummy } @@ -155,3 +157,21 @@ teardown() { unstub cache_dummy } + +@test 'Existing file-based restore to absolute path' { + export BUILDKITE_PLUGIN_CACHE_RESTORE=file + export BUILDKITE_PLUGIN_CACHE_PATH=/tmp/tests/data/my_files + + stub cache_dummy \ + 'exists \* : exit 0' \ + "get \* \* : echo restoring \$2 to \$3" + + run "$PWD/hooks/post-checkout" + + assert_success + assert_output --partial 'Cache hit at file level' + assert_output --partial 'Cache is compressed, uncompressing with tgz...' + assert_output --partial "with options xzPf" + + unstub cache_dummy +} diff --git a/tests/post-checkout-zip.bats b/tests/post-checkout-zip.bats index 0df6aa6..b47cc2f 100644 --- a/tests/post-checkout-zip.bats +++ b/tests/post-checkout-zip.bats @@ -24,7 +24,7 @@ setup() { # stub is the same for all tests stub unzip \ - "-o \* \* : echo uncompressed \$3 into \$4" + "-o \* \* : echo uncompressed \$2 into \$3" } teardown() { @@ -138,7 +138,6 @@ teardown() { unstub cache_dummy } - @test 'Existing lower level restore works' { export BUILDKITE_PLUGIN_CACHE_RESTORE=all @@ -156,3 +155,21 @@ teardown() { unstub cache_dummy } + +@test 'Existing file-based restore to absolute path' { + export BUILDKITE_PLUGIN_CACHE_RESTORE=all + export BUILDKITE_PLUGIN_CACHE_PATH=/tmp/tests/data/my_files + + # Need to create a file here to be able to move it to restore path later were it will be removed + stub cache_dummy \ + 'exists \* : exit 0' \ + "get \* \* : mkdir -p $(dirname \$3) && touch \$3 && echo restoring \$2 to \$3" + + run "$PWD/hooks/post-checkout" + + assert_success + assert_output --partial 'Cache hit at file level' + assert_output --partial "Cache is compressed, uncompressing with zip" + + unstub cache_dummy +} diff --git a/tests/post-command-tgz.bats b/tests/post-command-tgz.bats index 1cfcc31..48460d3 100644 --- a/tests/post-command-tgz.bats +++ b/tests/post-command-tgz.bats @@ -27,11 +27,11 @@ setup() { export BUILDKITE_PIPELINE_SLUG="cache-pipeline" # stubs are the same for every test + stub tar \ + "\* \* \* : echo compressed \$2 into \$3 with options \$1" + stub cache_dummy \ "save \* \* : echo saving \$3 in \$2" - - stub tar \ - "czf \* \* : echo compressed \$2 into \$3" } teardown() { @@ -50,6 +50,7 @@ teardown() { assert_success assert_output --partial 'Saving file-level cache' assert_output --partial 'Compressing tests/data/my_files with tgz' + assert_output --partial "with options czf" } @test "Step-level saving" { @@ -106,3 +107,19 @@ teardown() { assert_output --partial 'Saving all-level cache' assert_output --partial 'Saving pipeline-level cache' } + + +@test 'Pipeline-level saving with absolute cache path' { + BUILDKITE_PLUGIN_CACHE_PATH="$(mktemp -d)" + export BUILDKITE_PLUGIN_CACHE_PATH + export BUILDKITE_PLUGIN_CACHE_SAVE=pipeline + + run "$PWD/hooks/post-command" + + assert_success + assert_output --partial 'Saving pipeline-level cache' + assert_output --partial "Compressing ${BUILDKITE_PLUGIN_CACHE_PATH} with tgz..." + assert_output --partial "with options czPf" + + rm -rf "${BUILDKITE_PLUGIN_CACHE_PATH}" +} diff --git a/tests/post-command-zip.bats b/tests/post-command-zip.bats index 6421f7d..d505ed0 100644 --- a/tests/post-command-zip.bats +++ b/tests/post-command-zip.bats @@ -107,3 +107,18 @@ teardown() { assert_output --partial 'Saving all-level cache' assert_output --partial 'Saving pipeline-level cache' } + +@test 'Pipeline-level saving with absolute cache path' { + BUILDKITE_PLUGIN_CACHE_PATH="$(mktemp -d)" + export BUILDKITE_PLUGIN_CACHE_PATH + export BUILDKITE_PLUGIN_CACHE_SAVE=pipeline + + run "$PWD/hooks/post-command" + + assert_success + assert_output --partial "Compressing ${BUILDKITE_PLUGIN_CACHE_PATH} with zip..." + assert_output --partial 'Saving pipeline-level cache' + + rm -rf "${BUILDKITE_PLUGIN_CACHE_PATH}" +} +