From 2a66d7d4d7b1b8fc1e4b255357175a37af85780e Mon Sep 17 00:00:00 2001 From: Remo Senekowitsch Date: Fri, 9 Aug 2024 20:39:15 +0200 Subject: [PATCH] Pin problem-specifications to a specific commit (#1950) The previous approach used a submodule to keep things somewhat stable. That worked well for the rust-tooling (exercise generator) which made use of the submodule. However, configlet continued to use its own cache. (see https://github.com/exercism/configlet/issues/816) This could lead to problems where the configlet cache and the submodule are out of sync and don't agree. The new approach ditches the submodule and makes everything use the configlet cache. Some helper scripts are responsible to make sure the cache is checked out at the pinned commit and a configlet wrapper sets the `--offile` flag to prevent configlet from updating the cache. --- .gitignore | 1 + .gitmodules | 3 -- ...ut_pinned_problem_specifications_commit.sh | 17 +++++++++++ bin/configlet_wrapper.sh | 29 +++++++++++++++++++ bin/get_problem_specifications_dir.sh | 13 +++++++++ bin/symlink_problem_specifications.sh | 4 +++ bin/update_problem_specifications.sh | 15 ++++++++++ justfile | 13 +++++---- problem-specifications | 1 - .../ci-tests/tests/bash_script_conventions.rs | 2 +- 10 files changed, 88 insertions(+), 10 deletions(-) create mode 100755 bin/checkout_pinned_problem_specifications_commit.sh create mode 100755 bin/configlet_wrapper.sh create mode 100755 bin/get_problem_specifications_dir.sh create mode 100755 bin/update_problem_specifications.sh delete mode 160000 problem-specifications diff --git a/.gitignore b/.gitignore index 7f0587770..3eea4c1c0 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ exercises/*/*/Cargo.lock clippy.log .vscode .prob-spec +problem-specifications diff --git a/.gitmodules b/.gitmodules index bf863ee5b..e69de29bb 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +0,0 @@ -[submodule "problem-specifications"] - path = problem-specifications - url = git@github.com:exercism/problem-specifications diff --git a/bin/checkout_pinned_problem_specifications_commit.sh b/bin/checkout_pinned_problem_specifications_commit.sh new file mode 100755 index 000000000..7f29be359 --- /dev/null +++ b/bin/checkout_pinned_problem_specifications_commit.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +set -euo pipefail + +cd "$(git rev-parse --show-toplevel)" + +PINNED_COMMIT_HASH="685ec55d9388937bbb3cc836b52b3ce27f208f37" + +dir="$(./bin/get_problem_specifications_dir.sh)" + +[ -d "$dir" ] || ./bin/configlet info &> /dev/null # initial population of cache + +if ! git -C "$dir" checkout --quiet --detach "$PINNED_COMMIT_HASH" &> /dev/null +then + # maybe the pinned commit hash was updated and the cache has to be refreshed + ./bin/configlet info &> /dev/null + git -C "$dir" checkout --quiet --detach "$PINNED_COMMIT_HASH" +fi diff --git a/bin/configlet_wrapper.sh b/bin/configlet_wrapper.sh new file mode 100755 index 000000000..ef58d28b9 --- /dev/null +++ b/bin/configlet_wrapper.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash +set -eo pipefail + +# This wrapper makes sure the problem-specifications repository is checked out +# at the pinned commit and the --offline flag is set for the relevant commands. + +cd "$(git rev-parse --show-toplevel)" + +[ -f ./bin/configlet ] || ./bin/fetch-configlet + +if [ "$#" == 0 ] +then + ./bin/configlet + exit +fi + +cmd="$1" ; shift + +if ! [ "$cmd" == "create" ] && ! [ "$cmd" == "sync" ] && ! [ "$cmd" == "info" ] +then + # problem-specifications independent commands + ./bin/configlet "$cmd" "$@" + exit +fi + +./bin/checkout_pinned_problem_specifications_commit.sh + +set -x # show the added --offile flag +./bin/configlet "$cmd" --offline "$@" diff --git a/bin/get_problem_specifications_dir.sh b/bin/get_problem_specifications_dir.sh new file mode 100755 index 000000000..2f0ea1aea --- /dev/null +++ b/bin/get_problem_specifications_dir.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -euo pipefail + +if [[ "$OSTYPE" == "linux-gnu"* ]]; then + prefix="${XDG_CACHE_HOME:-$HOME/.cache}" +elif [[ "$OSTYPE" == "darwin"* ]]; then + prefix="${XDG_CACHE_HOME:-$HOME/Library/Caches}" +else + echo "Unsupported OS: $OSTYPE" >&2 + exit 1 +fi + +echo -n "$prefix/exercism/configlet/problem-specifications" diff --git a/bin/symlink_problem_specifications.sh b/bin/symlink_problem_specifications.sh index bf86ebaa9..119579e03 100755 --- a/bin/symlink_problem_specifications.sh +++ b/bin/symlink_problem_specifications.sh @@ -3,6 +3,10 @@ set -eo pipefail cd "$(git rev-parse --show-toplevel)" +[ -e "problem-specifications" ] || ln -s "$(./bin/get_problem_specifications_dir.sh)" "problem-specifications" + +./bin/checkout_pinned_problem_specifications_commit.sh + for exercise in exercises/practice/*; do name="$(basename "$exercise")" if [ -d "problem-specifications/exercises/$name" ]; then diff --git a/bin/update_problem_specifications.sh b/bin/update_problem_specifications.sh new file mode 100755 index 000000000..bb32bd47f --- /dev/null +++ b/bin/update_problem_specifications.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +set -euo pipefail + +cd "$(git rev-parse --show-toplevel)" + +./bin/checkout_pinned_problem_specifications_commit.sh + +dir="$(./bin/get_problem_specifications_dir.sh)" + +git -C "$dir" checkout --quiet main +git -C "$dir" pull --quiet + +new_commit_hash="$(git -C "$dir" rev-parse main)" + +sed -i "s/^PINNED_COMMIT_HASH=.*$/PINNED_COMMIT_HASH=\"$new_commit_hash\"/g" ./bin/checkout_pinned_problem_specifications_commit.sh diff --git a/justfile b/justfile index ee2936d19..8151c2420 100644 --- a/justfile +++ b/justfile @@ -1,14 +1,17 @@ _default: just --list --unsorted -# configlet wrapper, uses problem-specifications submodule -configlet *args="": - @[ -f bin/configlet ] || bin/fetch-configlet - ./bin/configlet {{ args }} +# configlet wrapper, uses pinned problem-specifications commit +@configlet *args="": + ./bin/configlet_wrapper.sh {{ args }} + +# update the pinned commit hash +update-problem-specs: + ./bin/update_problem_specifications.sh # generate a new uuid straight to your clipboard uuid: - ./bin/configlet uuid | tr -d '[:space:]' | wl-copy + just configlet uuid | tr -d '[:space:]' | wl-copy # simulate CI locally (WIP) test: diff --git a/problem-specifications b/problem-specifications deleted file mode 160000 index 6c44c8323..000000000 --- a/problem-specifications +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 6c44c83239e5d8dc6a7d36e800ece2548d106a65 diff --git a/rust-tooling/ci-tests/tests/bash_script_conventions.rs b/rust-tooling/ci-tests/tests/bash_script_conventions.rs index 95f0792ce..907c2077e 100644 --- a/rust-tooling/ci-tests/tests/bash_script_conventions.rs +++ b/rust-tooling/ci-tests/tests/bash_script_conventions.rs @@ -61,7 +61,7 @@ fn error_handling_flags() { for_all_scripts(|file_name| { let contents = std::fs::read_to_string(PathBuf::from("bin").join(file_name)).unwrap(); assert!( - contents.contains("set -eo pipefail"), + contents.contains("set -euo pipefail") || contents.contains("set -eo pipefail"), "'{file_name}' should set error handling flags 'set -eo pipefail'" ); })