diff --git a/bin/generate_practice_exercise b/bin/generate_practice_exercise index 6bc91fa5..8f854217 100755 --- a/bin/generate_practice_exercise +++ b/bin/generate_practice_exercise @@ -1,13 +1,35 @@ #!/usr/bin/env bash -# Exit if anything fails. +# 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 -# If argument not provided, print usage and exit -if [ -z "$1" ]; then - echo "Usage: bin/generate_practice_exercise " +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 -fi +} + +die() { echo >&2 "$*"; exit 1; } + +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." +} if ! [ -x "$(command -v jq)" ]; then echo "jq is required. Please install jq and make sure it is on the $PATH: https://stedolan.github.io/jq/download/" >&2 @@ -19,28 +41,62 @@ if ! [ -x "$(command -v emacs)" ]; then exit 1 fi -SLUG="$1" -exercise_dir="exercises/practice/${SLUG}" +require_files_template "solution" +require_files_template "test" +require_files_template "example" -download() { - file="$1" - url="$2" - curl --silent --show-error --fail --retry 3 --max-time 3 \ - --output "$file" "$url" -} +[[ -f ./bin/fetch-configlet ]] || die "Run this script from the repo's root directory." + +author='' +difficulty='' +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 + +if [[ -z "${difficulty}" ]]; then + read -rp "What's the difficulty for ${slug}? " difficulty +fi -# build configlet echo "Fetching latest version of configlet..." ./bin/fetch-configlet -# Preparing config.json echo "Adding instructions and configuration files..." -./bin/configlet create --practice-exercise "$SLUG" +./bin/configlet create --practice-exercise "${slug}" --author "${author}" --difficulty "${difficulty}" + +filter='.exercises.practice = (.exercises.practice | sort_by(.difficulty, .slug))' +jq "${filter}" config.json > config.sorted && mv config.sorted config.json pushd tools -emacs -batch -l install-packages.el -l practice-exercise-generator.el --eval "(exercism/generate-practice-exercise \"$SLUG\")" +emacs -batch -l install-packages.el -l practice-exercise-generator.el --eval "(exercism/generate-practice-exercise \"${slug}\")" popd -echo "All stub files were created. After implementing the solution, tests and configuration, please run:" -echo " ./bin/configlet sync --update --tests --exercise ${SLUG}" -echo " ./bin/configlet fmt --update --yes --exercise ${SLUG}" +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") + +cat << NEXT_STEPS + +The test specifications have been copied into the test methods stubs by the generator. + +Your next steps are: +- Implement the test suite in $(jq -r '.test' <<< "${files}") + - The tests are 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" +- Review the stub solution in $(jq -r '.solution' <<< "${files}") +- Implement the example solution in $(jq -r '.example' <<< "${files}") +- Verify the example solution passes the tests by running 'bin/test-examples' +- Validate CI using 'bin/configlet lint' and 'bin/configlet fmt' +NEXT_STEPS