Skip to content

Commit 7f22595

Browse files
Add bin/add-practice-exercise (#544)
1 parent 6df5dcd commit 7f22595

File tree

1 file changed

+89
-0
lines changed

1 file changed

+89
-0
lines changed

bin/add-practice-exercise

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
#!/usr/bin/env bash
2+
3+
# Synopsis:
4+
# Scaffold the files for a new practice exercise.
5+
# After creating the exercise, follow the instructions in the output.
6+
7+
# Example:
8+
# bin/add-practice-exercise two-fer
9+
10+
# Example with difficulty:
11+
# bin/add-practice-exercise -d 5 two-fer
12+
13+
# Example with author and difficulty:
14+
# bin/add-practice-exercise -a foo -d 3 two-fer
15+
16+
set -euo pipefail
17+
scriptname=$0
18+
19+
help_and_exit() {
20+
echo >&2 "Scaffold the files for a new practice exercise."
21+
echo >&2 "Usage: ${scriptname} [-h] [-a author] [-d difficulty] <exercise-slug>"
22+
echo >&2 "Where: author is the GitHub username of the exercise creator."
23+
echo >&2 "Where: difficulty is between 1 (easiest) to 10 (hardest)."
24+
exit 1
25+
}
26+
27+
die() { echo >&2 "$*"; exit 1; }
28+
29+
required_tool() {
30+
command -v "${1}" >/dev/null 2>&1 ||
31+
die "${1} is required but not installed. Please install it and make sure it's in your PATH."
32+
}
33+
34+
require_files_template() {
35+
jq -e --arg key "${1}" '.files[$key] | length > 0' config.json > /dev/null ||
36+
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."
37+
}
38+
39+
required_tool jq
40+
41+
require_files_template "solution"
42+
require_files_template "test"
43+
require_files_template "example"
44+
45+
[[ -f ./bin/fetch-configlet ]] || die "Run this script from the repo's root directory."
46+
47+
author=''
48+
difficulty='4'
49+
while getopts :ha:d: opt; do
50+
case $opt in
51+
h) help_and_exit ;;
52+
a) author=$OPTARG ;;
53+
d) difficulty=$OPTARG ;;
54+
?) echo >&2 "Unknown option: -$OPTARG"; help_and_exit ;;
55+
esac
56+
done
57+
shift "$((OPTIND - 1))"
58+
59+
(( $# >= 1 )) || help_and_exit
60+
61+
slug="${1}"
62+
63+
if [[ -z "${author}" ]]; then
64+
read -rp 'Your GitHub username: ' author
65+
fi
66+
67+
./bin/fetch-configlet
68+
./bin/configlet create --practice-exercise "${slug}" --author "${author}" --difficulty "${difficulty}"
69+
70+
filter='.exercises.practice = (.exercises.practice | sort_by(.difficulty, .slug))'
71+
jq "${filter}" config.json > config.sorted && mv config.sorted config.json
72+
73+
exercise_dir="exercises/practice/${slug}"
74+
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")
75+
76+
cp exercises/practice/hello-world/.busted "exercises/practice/${slug}/.busted"
77+
78+
cat << NEXT_STEPS
79+
80+
Your next steps are:
81+
- Create the test suite in $(jq -r '.test' <<< "${files}")
82+
- The tests should be based on the canonical data at 'https://github.com/exercism/problem-specifications/blob/main/exercises/${slug}/canonical-data.json'
83+
- Any test cases you don't implement, mark them in 'exercises/practice/${slug}/.meta/tests.toml' with "include = false"
84+
- Create the example solution in $(jq -r '.example' <<< "${files}")
85+
- Verify the example solution passes the tests by running 'bin/test-all'
86+
- Create the stub solution in $(jq -r '.solution' <<< "${files}")
87+
- Update the 'difficulty' value for the exercise's entry in the 'config.json' file in the repo's root
88+
- Validate CI using 'bin/configlet lint' and 'bin/configlet fmt'
89+
NEXT_STEPS

0 commit comments

Comments
 (0)