diff --git a/bin/add-exercise b/bin/add-exercise deleted file mode 100755 index b0c77eb..0000000 --- a/bin/add-exercise +++ /dev/null @@ -1,81 +0,0 @@ -#!/usr/bin/env bash - -set -euo pipefail -scriptname=$0 - -help_and_exit() { - echo >&2 "Populates a new directory for a practice exercise." - echo >&2 "Usage: ${scriptname} [-h] [-a author] " - echo >&2 "Where: author is the github username of the exercise creator." - exit 1 -} - -die() { echo >&2 "$*"; exit 1; } - -required_tool() { - command -v "$1" >/dev/null 2>&1 || - die "$1 is required but not installed. Please install it and make sure it's in your PATH." -} - -(( $# >= 1 )) || help_and_exit - -required_tool jq -required_tool curl - -[[ -f ./bin/fetch-configlet ]] || die "run this script from the repo's root directory." - -author='' -while getopts :ha: opt; do - case $opt in - h) help_and_exit ;; - a) author=$OPTARG ;; - ?) echo >&2 "Unknown option: -$OPTARG"; help_and_exit ;; - esac -done -shift "$((OPTIND - 1))" - -slug="${1}" - -# Create entry for exercise in config.json and exercise files -./bin/fetch-configlet -./bin/configlet create --practice-exercise "${slug}" - -cp ./libs/exercism/test "exercises/practice/${slug}/libs/exercism/test" - -cat << END_TEST > "exercises/practice/${slug}/test.8th" -"${slug}.8th" f:include -needs exercism/test -with: test -N tests - -$(curl --silent "https://raw.githubusercontent.com/exercism/problem-specifications/main/exercises/${slug}/canonical-data.json") - -end-of-tests -;with -END_TEST - -if [[ -z $author ]]; then - echo - read -rp 'Your github username: ' author -fi - -conf="exercises/practice/${slug}/.meta/config.json" -jq --arg author "${author}" \ - '.authors = [$author]' "${conf}" > "${conf}.tmp" \ -&& mv "${conf}.tmp" "${conf}" - -echo -find "exercises/practice/${slug}" -type f -ls - -cat << NEXT_STEPS - -Your next steps are: -- Create the test suite in 'exercises/practice/${slug}/test.8th' - based on the canonical data at 'https://github.com/exercism/problem-specifications/blob/main/exercises/${slug}/canonical-data.json' - - Any test cases you don't implement, mark them in 'exercises/practice/${slug}/.meta/tests.toml' with "include = false" -- Create the example solution in 'exercises/practice/${slug}/.meta/example.8th' -- Verify the example solution by running 'bin/test-no-docker ${slug}' -- Create the stub solution in 'exercises/practice/${slug}/${slug}.8th' -- Update the 'difficulty' value for the exercise's entry in the 'config.json' file -- Validate CI using 'bin/configlet lint' and 'bin/configlet fmt' -NEXT_STEPS diff --git a/bin/add-practice-exercise b/bin/add-practice-exercise new file mode 100755 index 0000000..7316541 --- /dev/null +++ b/bin/add-practice-exercise @@ -0,0 +1,98 @@ +#!/usr/bin/env bash + +# Synopsis: +# Scaffold the files for a new practice exercise. +# After creating the exercise, follow the instructions in the output. + +# Example: +# bin/add-practice-exercise two-fer + +# Example with difficulty: +# bin/add-practice-exercise -d 5 two-fer + +# Example with author and difficulty: +# bin/add-practice-exercise -a foo -d 3 two-fer + +set -euo pipefail +scriptname=$0 + +help_and_exit() { + echo >&2 "Scaffold the files for a new practice exercise." + echo >&2 "Usage: ${scriptname} [-h] [-a author] [-d difficulty] " + echo >&2 "Where: author is the GitHub username of the exercise creator." + echo >&2 "Where: difficulty is between 1 (easiest) to 10 (hardest)." + exit 1 +} + +die() { echo >&2 "$*"; exit 1; } + +required_tool() { + command -v "${1}" >/dev/null 2>&1 || + die "${1} is required but not installed. Please install it and make sure it's in your PATH." +} + +require_files_template() { + jq -e --arg key "${1}" '.files[$key] | length > 0' config.json > /dev/null || + die "The '.files.${1}' array in the 'config.json' file is empty. Please add at least one file. See https://exercism.org/docs/building/tracks/config-json#h-files for more information." +} + +required_tool jq + +require_files_template "solution" +require_files_template "test" +require_files_template "example" + +[[ -f ./bin/fetch-configlet ]] || die "Run this script from the repo's root directory." + +author='' +difficulty='1' +while getopts :ha:d: opt; do + case $opt in + h) help_and_exit ;; + a) author=$OPTARG ;; + d) difficulty=$OPTARG ;; + ?) echo >&2 "Unknown option: -$OPTARG"; help_and_exit ;; + esac +done +shift "$((OPTIND - 1))" + +(( $# >= 1 )) || help_and_exit + +slug="${1}" + +if [[ -z "${author}" ]]; then + read -rp 'Your GitHub username: ' author +fi + +./bin/fetch-configlet +./bin/configlet create --practice-exercise "${slug}" --author "${author}" --difficulty "${difficulty}" + +exercise_dir="exercises/practice/${slug}" +files=$(jq -r --arg dir "${exercise_dir}" '.files | to_entries | map({key: .key, value: (.value | map("'"'"'" + $dir + "/" + . + "'"'"'") | join(" and "))}) | from_entries' "${exercise_dir}/.meta/config.json") + +cp ./libs/exercism/test "exercises/practice/${slug}/libs/exercism/test" + +cat << END_TEST > "exercises/practice/${slug}/test.8th" +"${slug}.8th" f:include +needs exercism/test +with: test +N tests + +$(curl --silent "https://raw.githubusercontent.com/exercism/problem-specifications/main/exercises/${slug}/canonical-data.json") + +end-of-tests +;with +END_TEST + +cat << NEXT_STEPS + +Your next steps are: +- Create the test suite in $(jq -r '.test' <<< "${files}") + - The tests should be based on the canonical data at 'https://github.com/exercism/problem-specifications/blob/main/exercises/${slug}/canonical-data.json' + - Any test cases you don't implement, mark them in 'exercises/practice/${slug}/.meta/tests.toml' with "include = false" +- Create the example solution in $(jq -r '.example' <<< "${files}") +- Verify the example solution passes the tests by running 'bin/verify-exercises ${slug}' +- Create the stub solution in $(jq -r '.solution' <<< "${files}") +- Update the 'difficulty' value for the exercise's entry in the 'config.json' file in the repo's root +- Validate CI using 'bin/configlet lint' and 'bin/configlet fmt' +NEXT_STEPS