From 464e3f02892f84f644596e6a0d1a35c0e1df2bb5 Mon Sep 17 00:00:00 2001 From: Michael de Wit Date: Mon, 18 Dec 2017 17:01:47 +0100 Subject: [PATCH] Add option to control cache key (folder). Fixes #12 and #13 --- DOCS.md | 23 +++++++++++++++++++++++ cacher.sh | 41 +++++++++++++++++++++++++++++------------ 2 files changed, 52 insertions(+), 12 deletions(-) diff --git a/DOCS.md b/DOCS.md index 15be8a8..768e2b0 100644 --- a/DOCS.md +++ b/DOCS.md @@ -7,6 +7,7 @@ The following parameters are used to configure the plugin: - **rebuild** - instruct plugin to rebuild cache, can be `true` or `false` - **mount** - list of folders or files to cache - **ttl** - maximum cache lifetime in days +- **cache_key** - list of environment variables to use for constructing the cache path ## Examples ```yaml @@ -55,6 +56,28 @@ pipeline: The example above shows a situation where cached items older than 7 days will not be restored (they will be removed instead). Only the restore step needs the `ttl` parameter. +## Using the cache_key option +By default, this plugin uses the repo owner, repo name, and job number to construct a cache key. Say the repository owner is `foo`, the repository name is `bar`, and the job number is `1`, +the cache key (folder) the plugin will use for the build will be `foo/bar/1`. +If this is not optimal for your specific situation, it is possible to modify the cache key. For example, let's say that your project differs quite a bit between different branches, you may want to include the branch somewhere in the cache key: + +```yaml +pipeline: + restore-cache: + image: drillster/drone-volume-cache + restore: true + mount: + - ./node_modules + # Mount the cache volume, needs "Trusted" + volumes: + - /tmp/cache:/cache + cache_key: [ DRONE_REPO_OWNER, DRONE_REPO_NAME, DRONE_BRANCH, DRONE_JOB_NUMBER ] +``` + +This would lead to the following cache key if a build is triggered for the master branch (and the rest of the situation is the same as the example illustrated above): `foo/bar/master/1`. + +In theory you could even use this to share cache between different projects, but extreme caution is advised doing so. + ## Clearing Cache Should you want to clear the cache for a project, you can do so by including `[CLEAR CACHE]` in the commit message. The entire cache folder for the project will be cleared before it is restored. The rebuilding of cache will proceed as normal. diff --git a/cacher.sh b/cacher.sh index 52338de..20531d1 100644 --- a/cacher.sh +++ b/cacher.sh @@ -19,32 +19,49 @@ if [[ $DRONE_COMMIT_MESSAGE == *"[NO CACHE]"* ]]; then exit 0 fi +CACHE_PATH="$DRONE_REPO_OWNER/$DRONE_REPO_NAME/$DRONE_JOB_NUMBER" +if [[ -n "$PLUGIN_CACHE_KEY" ]]; then + function join_by { local IFS="$1"; shift; echo "$*"; } + IFS=','; read -ra CACHE_PATH_VARS <<< "$PLUGIN_CACHE_KEY" + CACHE_PATH_VALUES=() + for env_var in "${CACHE_PATH_VARS[@]}"; do + env_var_value="${!env_var}" + + if [[ -z "$env_var_value" ]]; then + echo "Warning! Environment variable '${env_var}' does not contain a value, it will be ignored!" + else + CACHE_PATH_VALUES+=("${env_var_value}") + fi + done + CACHE_PATH=$(join_by / "${CACHE_PATH_VALUES[@]}") +fi + IFS=','; read -ra SOURCES <<< "$PLUGIN_MOUNT" if [[ -n "$PLUGIN_REBUILD" && "$PLUGIN_REBUILD" == "true" ]]; then # Create cache for source in "${SOURCES[@]}"; do if [ -d "$source" ]; then echo "Rebuilding cache for folder $source..." - mkdir -p "/cache/$DRONE_REPO_OWNER/$DRONE_REPO_NAME/$DRONE_JOB_NUMBER/$source" && \ - rsync -aHA --delete "$source/" "/cache/$DRONE_REPO_OWNER/$DRONE_REPO_NAME/$DRONE_JOB_NUMBER/$source" + mkdir -p "/cache/$CACHE_PATH/$source" && \ + rsync -aHA --delete "$source/" "/cache/$CACHE_PATH/$source" elif [ -f "$source" ]; then echo "Rebuilding cache for file $source..." source_dir=$(dirname $source) - mkdir -p "/cache/$DRONE_REPO_OWNER/$DRONE_REPO_NAME/$DRONE_JOB_NUMBER/$source_dir" && \ - rsync -aHA --delete "$source" "/cache/$DRONE_REPO_OWNER/$DRONE_REPO_NAME/$DRONE_JOB_NUMBER/$source_dir/" + mkdir -p "/cache/$CACHE_PATH/$source_dir" && \ + rsync -aHA --delete "$source" "/cache/$CACHE_PATH/$source_dir/" else echo "$source does not exist, removing from cached folder..." - rm -rf "/cache/$DRONE_REPO_OWNER/$DRONE_REPO_NAME/$DRONE_JOB_NUMBER/$source" + rm -rf "/cache/$CACHE_PATH/$source" fi done elif [[ -n "$PLUGIN_RESTORE" && "$PLUGIN_RESTORE" == "true" ]]; then # Remove files older than TTL if [[ -n "$PLUGIN_TTL" && "$PLUGIN_TTL" > "0" ]]; then if [[ $PLUGIN_TTL =~ ^[0-9]+$ ]]; then - if [ -d "/cache/$DRONE_REPO_OWNER/$DRONE_REPO_NAME/$DRONE_JOB_NUMBER" ]; then + if [ -d "/cache/$CACHE_PATH" ]; then echo "Removing files and (empty) folders older than $PLUGIN_TTL days..." - find "/cache/$DRONE_REPO_OWNER/$DRONE_REPO_NAME/$DRONE_JOB_NUMBER" -type f -ctime +$PLUGIN_TTL -delete - find "/cache/$DRONE_REPO_OWNER/$DRONE_REPO_NAME/$DRONE_JOB_NUMBER" -type d -ctime +$PLUGIN_TTL -empty -delete + find "/cache/$CACHE_PATH" -type f -ctime +$PLUGIN_TTL -delete + find "/cache/$CACHE_PATH" -type d -ctime +$PLUGIN_TTL -empty -delete fi else echo "Invalid value for ttl, please enter a positive integer. Plugin will ignore ttl." @@ -52,15 +69,15 @@ elif [[ -n "$PLUGIN_RESTORE" && "$PLUGIN_RESTORE" == "true" ]]; then fi # Restore from cache for source in "${SOURCES[@]}"; do - if [ -d "/cache/$DRONE_REPO_OWNER/$DRONE_REPO_NAME/$DRONE_JOB_NUMBER/$source" ]; then + if [ -d "/cache/$CACHE_PATH/$source" ]; then echo "Restoring cache for folder $source..." mkdir -p "$source" && \ - rsync -aHA --delete "/cache/$DRONE_REPO_OWNER/$DRONE_REPO_NAME/$DRONE_JOB_NUMBER/$source/" "$source" - elif [ -f "/cache/$DRONE_REPO_OWNER/$DRONE_REPO_NAME/$DRONE_JOB_NUMBER/$source" ]; then + rsync -aHA --delete "/cache/$CACHE_PATH/$source/" "$source" + elif [ -f "/cache/$CACHE_PATH/$source" ]; then echo "Restoring cache for file $source..." source_dir=$(dirname $source) mkdir -p "$source_dir" && \ - rsync -aHA --delete "/cache/$DRONE_REPO_OWNER/$DRONE_REPO_NAME/$DRONE_JOB_NUMBER/$source" "$source_dir/" + rsync -aHA --delete "/cache/$CACHE_PATH/$source" "$source_dir/" else echo "No cache for $source" fi