Skip to content

Commit 7580e89

Browse files
Update bin/add-exercise (#452)
1 parent 3056351 commit 7580e89

File tree

1 file changed

+72
-23
lines changed

1 file changed

+72
-23
lines changed

bin/add-exercise

Lines changed: 72 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,87 @@
11
#!/usr/bin/env bash
22

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-exercise two-fer
9+
10+
# Example with difficulty:
11+
# bin/add-exercise -d 5 two-fer
12+
13+
# Example with author and difficulty:
14+
# bin/add-exercise -a foo -d 3 two-fer
15+
316
set -euo pipefail
17+
scriptname=$0
418

5-
if [ $# -ne 1 ]; then
6-
echo "Usage: bin/add-exercise <exercise-slug>"
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)."
724
exit 1
8-
fi
25+
}
926

10-
command -v jq >/dev/null 2>&1 || {
11-
echo >&2 "jq is required but not installed. Please install it and make sure it's in your PATH."
12-
exit 1
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."
1332
}
14-
command -v curl >/dev/null 2>&1 || {
15-
echo >&2 "curl is required but not installed. Please install it and make sure it's in your PATH."
16-
exit 1
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."
1737
}
1838

19-
bin/fetch-configlet
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
2060

21-
# Add entry for exercise in config.json
2261
slug="${1}"
23-
# shellcheck disable=SC2001
24-
name=$(echo "${slug}" | sed 's/\b\w/\u&/g')
25-
uuid=$(bin/configlet uuid)
26-
jq --arg slug "${slug}" --arg uuid "${uuid}" --arg name "${name}" \
27-
'.exercises.practice += [{slug: $slug, name: $name, uuid: $uuid, practices: [], prerequisites: [], difficulty: 1}]' \
28-
config.json | sed 's/"average_run_time": 5/"average_run_time": 5.0/' > config.json.tmp && mv config.json.tmp config.json
2962

30-
# Sync the exercise
31-
bin/configlet sync --update --yes --tests include --filepaths --metadata --docs --exercise "${slug}"
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
3272

3373
exercise_dir="exercises/practice/${slug}"
34-
exercise_files=$(jq -r '.files[][]' "${exercise_dir}/.meta/config.json")
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")
3575

36-
for file in ${exercise_files}; do
37-
touch "${exercise_dir}/${file}"
38-
done
76+
cat << NEXT_STEPS
77+
78+
Your next steps are:
79+
- Create the test suite in $(jq -r '.test' <<< "${files}")
80+
- The tests should be based on the canonical data at 'https://github.com/exercism/problem-specifications/blob/main/exercises/${slug}/canonical-data.json'
81+
- Any test cases you don't implement, mark them in 'exercises/practice/${slug}/.meta/tests.toml' with "include = false"
82+
- Create the example solution in $(jq -r '.example' <<< "${files}")
83+
- Verify the example solution passes the tests by running 'bin/run-tests ${slug}'
84+
- Create the stub solution in $(jq -r '.solution' <<< "${files}")
85+
- Update the 'difficulty' value for the exercise's entry in the 'config.json' file in the repo's root
86+
- Validate CI using 'bin/configlet lint' and 'bin/configlet fmt'
87+
NEXT_STEPS

0 commit comments

Comments
 (0)