Skip to content

Commit e24a11d

Browse files
Merge branch 'exercism:main' into main
2 parents 251ef7e + d11c357 commit e24a11d

923 files changed

Lines changed: 11469 additions & 5502 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
name: Deprecated
2+
3+
on:
4+
pull_request:
5+
paths:
6+
- "exercises/**"
7+
push:
8+
branches:
9+
- main
10+
workflow_dispatch:
11+
12+
jobs:
13+
test-deprecated:
14+
name: Check for deprecated exercises
15+
runs-on: ubuntu-24.04
16+
steps:
17+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
18+
with:
19+
fetch-depth: 0
20+
- name: Test deprecated exercises using test-deprecated-exercises
21+
run: bin/test-deprecated-exercises

.github/workflows/java.yml

Lines changed: 55 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@ jobs:
1515
name: Check if tests compile cleanly with starter sources
1616
runs-on: ubuntu-24.04
1717
steps:
18-
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
19-
- name: Set up JDK 1.17
20-
uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00
18+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
19+
- name: Set up JDK 21
20+
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654
2121
with:
22-
java-version: 17
22+
java-version: 21
2323
distribution: "temurin"
2424
- name: Check if tests compile cleanly with starter sources
2525
run: ./gradlew compileStarterTestJava --continue
@@ -29,26 +29,70 @@ jobs:
2929
name: Lint Java files using Checkstyle
3030
runs-on: ubuntu-24.04
3131
steps:
32-
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
33-
- name: Set up JDK 1.17
34-
uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00
32+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
33+
- name: Set up JDK 21
34+
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654
3535
with:
36-
java-version: 17
36+
java-version: 21
3737
distribution: "temurin"
3838
- name: Run checkstyle
3939
run: ./gradlew check --exclude-task test --continue
4040
working-directory: exercises
4141

42-
test:
42+
test-all:
4343
name: Test all exercises using java-test-runner
44+
if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
4445
runs-on: ubuntu-24.04
4546
steps:
46-
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
47+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
4748
- name: Test all exercises using java-test-runner
4849
run: bin/test-with-test-runner
50+
- name: Print summary
51+
run: |
52+
if [ -f exercises/build/summary.txt ]; then
53+
echo "===== TEST SUMMARY ====="
54+
cat exercises/build/summary.txt
55+
echo "========================"
56+
else
57+
echo "===== ALL TESTS PASSED ====="
58+
echo "No summary file was generated."
59+
echo "============================="
60+
fi
61+
if: always()
4962
- name: Archive test results
50-
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
63+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
5164
with:
5265
name: test-results
5366
path: exercises/**/build/results.json
5467
if: failure()
68+
69+
test-changed:
70+
name: Test changed exercises using gradlew
71+
if: github.event_name == 'pull_request'
72+
runs-on: ubuntu-24.04
73+
steps:
74+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
75+
with:
76+
fetch-depth: 0
77+
- name: Test changed exercises using java-test-runner
78+
run: bin/test-changed-exercise
79+
- name: Print summary
80+
run: |
81+
if [ -f exercises/build/summary.txt ]; then
82+
echo "===== TEST SUMMARY ====="
83+
cat exercises/build/summary.txt
84+
echo "========================"
85+
else
86+
echo "===== ALL TESTS PASSED ====="
87+
echo "No summary file was generated."
88+
echo "============================="
89+
fi
90+
if: always()
91+
- name: Archive test results
92+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
93+
with:
94+
name: test-results
95+
path: |
96+
exercises/**/build/results.txt
97+
exercises/**/build/results.json
98+
if: failure()

.github/workflows/markdown.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,6 @@ jobs:
1717
name: Lint Markdown files
1818
runs-on: ubuntu-24.04
1919
steps:
20-
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
20+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
2121
- name: Lint markdown
22-
uses: DavidAnson/markdownlint-cli2-action@992badcdf24e3b8eb7e87ff9287fe931bcb00c6e
22+
uses: DavidAnson/markdownlint-cli2-action@6b51ade7a9e4a75a7ad929842dd298a3804ebe8b

CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ Each problem/submodule has three source sets:
209209

210210
### Update/sync Gradle versions
211211

212-
Please read [How to Update Gradle](../reference/how-to-update-gradle.md)
212+
Please read [How to Update Gradle](reference/how-to-update-gradle.md)
213213

214214
## Contributing to Concept Exercises
215215

POLICIES.md

Lines changed: 8 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ Our policies are not set-in-stone. They represent directions chosen at a point i
2424
| | [Ignore noninitial tests](#ignore-noninitial-tests) |
2525
| | [Multiple file submissions](#multiple-file-submissions) |
2626
| | [Name test class after class under test](#name-test-class-after-class-under-test) |
27-
| | [Add hint for the first exercises without starter implementation](#add-hint-for-the-first-exercises-without-starter-implementation) |
2827
| | [Reference tutorial in the first exercises](#reference-tutorial-in-the-first-exercises) |
2928
| | [Avoid returning null](#avoid-returning-null) |
3029
| | [Prefer AssertJ assertions](#prefer-assertj-assertions) |
@@ -44,16 +43,14 @@ References: [[1](https://github.com/exercism/java/issues/177#issuecomment-261291
4443

4544
### Starter implementations
4645

47-
> - Exercises of difficulty 4 or lower: provide stubs for all required constructors and methods. This means that you need to provide stubs for those constructors or methods that are necessary to pass all tests. E.g. stubs for private methods may be skipped.
48-
> Stubs should include the following body:
46+
> Provide stubs for all required constructors and methods. This means that you need to provide stubs for those constructors or methods that are necessary to pass all tests. E.g. stubs for private methods may be skipped.
47+
> Stubs should include the following body:
4948
>
50-
> ```java
51-
> throw new UnsupportedOperationException("Delete this statement and write your own implementation.");
52-
> ```
53-
>
54-
> - Exercises of difficulty 5 or higher: copy the StubTemplate.java file (provided in [this template file](https://github.com/exercism/java/blob/main/resources/exercise-template/src/main/java/ExerciseName.java)) and rename it to fit the exercise. For example, for the exercise linked-list the file could be named LinkedList.java. Then either (1) add hints to the hints.md file (which gets merged into the README.md for the exercise) or (2) provide stubs as above for exercises that demand complicated method signatures.
49+
> ```java
50+
> throw new UnsupportedOperationException("Delete this statement and write your own implementation.");
51+
> ```
5552
56-
References: [[1](https://github.com/exercism/java/issues/178)], [[2](https://github.com/exercism/java/pull/683#discussion_r125506930)], [[3](https://github.com/exercism/java/issues/977)], [[4](https://github.com/exercism/java/issues/1721)]
53+
Reference: [[1](https://github.com/exercism/java/issues/2133)]
5754
5855
### Avoid using final
5956
@@ -126,27 +123,14 @@ References: [[1](https://github.com/exercism/java/issues/395#issue-215734887)]
126123
127124
References: [[1](https://github.com/exercism/java/issues/697)]
128125
129-
### Add hint for the first exercises without starter implementation
130-
131-
> According to the starter implementation policy, any exercise with difficulty 4 or lower should have starter implementation.
132-
> Any exercise with difficulty 5 or above will have no starter implementation (unless its signature is very complicated).
133-
> This could be confusing to users when tackling their first exercise with difficulty 5 when they are used to starter implementation being provided.
134-
>
135-
> Therefore a hints.md file should be added to the .meta directory for every exercise with difficulty 5.
136-
> This file should explain what they need to do when there is no starter implementation.
137-
> The files should all be the same so you can copy it from any other exercise with difficulty 5, e.g. [flatten-array](https://github.com/exercism/java/tree/main/exercises/pratice/flatten-array/.meta/hints.md).
138-
>
139-
> We add the file to every exercise with difficulty 5 because the structure of the track means that we don't know which exercise will be the first one without starter implementation that a user will be faced with.
140-
141-
References: [[1](https://github.com/exercism/java/issues/1075)]
142-
143126
### Reference tutorial in the first exercises
144127
145128
> The hello world exercise has an extensive tutorial on how to solve exercism exercises.
146129
> This tutorial would probably be useful to have as a reference when solving some of the other earlier exercises as well.
147-
> Therefore any exercise with difficulty less than 3 should have a hints.md file which references [the hello world tutorial](https://github.com/exercism/java/blob/main/exercises/practice/hello-world/.docs/instructions.append.md#tutorial).
130+
> Therefore any exercise with difficulty less than 3 should have a instructions.append.md file which references [the hello world tutorial](https://github.com/exercism/java/blob/main/exercises/practice/hello-world/.docs/instructions.append.md#tutorial).
148131
149132
References: [[1](https://github.com/exercism/java/issues/1389)]
133+
Note: The PRs in the referenced issue uses hints.md, but this is now instructions.append.md (see [commit 52617354](https://github.com/exercism/java/commit/5261735435192b5b10535b2fcf41c81b638e5de5))
150134
151135
### Avoid returning null
152136

bin/test-changed-exercise

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
#!/usr/bin/env bash
2+
set -eo pipefail
3+
4+
# Determine the base branch of the PR
5+
BASE_BRANCH=${GITHUB_BASE_REF:-main}
6+
7+
# Fetch full history for proper diff
8+
git fetch origin "$BASE_BRANCH"
9+
10+
# Compute merge base
11+
MERGE_BASE=$(git merge-base HEAD origin/"$BASE_BRANCH")
12+
13+
# Get changed files relative to merge base
14+
changed_files=$(git diff --name-only "$MERGE_BASE" HEAD)
15+
16+
# If any Gradle build file changed, run the full suite and exit
17+
if echo "$changed_files" | grep -qE '\.(gradle|gradlew|bat)$|settings\.gradle'; then
18+
echo "Gradle build files changed, running full test suite..."
19+
./bin/test-with-test-runner
20+
exit 0
21+
fi
22+
23+
# Extract unique exercise directories
24+
changed_exercises=$(echo "$changed_files" | \
25+
grep -E '^exercises/(practice|concept)/[^/]+/.+\.java$' | \
26+
cut -d/ -f1-3 | sort -u)
27+
28+
if [ -z "$changed_exercises" ]; then
29+
echo "No relevant exercises changed, skipping tests."
30+
exit 0
31+
fi
32+
33+
# Print exercises
34+
echo "Changed exercises detected:"
35+
echo "$changed_exercises"
36+
echo "----------------------------------------"
37+
38+
summary_dir="exercises/build"
39+
summary_file="${summary_dir}/summary.txt"
40+
mkdir -p "$summary_dir"
41+
42+
# Run tests
43+
exit_code=0
44+
for dir in $changed_exercises; do
45+
slug=$(basename "$dir")
46+
47+
echo "========================================"
48+
echo "=== Running tests for $slug ==="
49+
echo "========================================"
50+
51+
results_path="$dir/build/results.txt"
52+
mkdir -p "$(dirname "$results_path")"
53+
54+
if [[ $dir == exercises/practice/* ]]; then
55+
./exercises/gradlew -p exercises ":practice:$slug:test" 2>&1 | tee "$results_path" || true
56+
elif [[ $dir == exercises/concept/* ]]; then
57+
./exercises/gradlew -p exercises ":concept:$slug:test" 2>&1 | tee "$results_path" || true
58+
fi
59+
60+
# Detect failure
61+
if grep -q "FAILED" "$results_path"; then
62+
exit_code=1
63+
64+
# Determine practice/slug or concept/slug
65+
relative_path=$(echo "$dir" | sed 's|^exercises/||')
66+
67+
# Create summary.txt with header only on first failure
68+
if [ ! -f "$summary_file" ]; then
69+
echo "The following exercises have test failures or test errors:" > "$summary_file"
70+
fi
71+
72+
# Append the correct path (practice/slug or concept/slug)
73+
echo "$relative_path" >> "$summary_file"
74+
fi
75+
76+
done
77+
78+
exit $exit_code

bin/test-deprecated-exercises

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#!/usr/bin/env bash
2+
set -eo pipefail
3+
4+
# Determine the base branch of the PR
5+
BASE_BRANCH=${GITHUB_BASE_REF:-main}
6+
7+
# Fetch full history for proper diff
8+
git fetch origin "$BASE_BRANCH"
9+
10+
# Compute merge base
11+
MERGE_BASE=$(git merge-base HEAD origin/"$BASE_BRANCH")
12+
13+
# Get changed files relative to merge base
14+
changed_files=$(git diff --name-only "$MERGE_BASE" HEAD)
15+
16+
# Extract unique exercise directories
17+
changed_exercises=$(echo "$changed_files" | grep -E '^exercises/(practice|concept)/' || true)
18+
changed_exercises=$(echo "$changed_exercises" | cut -d/ -f1-3 | sort -u)
19+
20+
# Early exit if no exercise changed
21+
if [ -z "$changed_exercises" ]; then
22+
echo "No exercises changed!"
23+
exit 0
24+
fi
25+
26+
# Load deprecated exercises from config.json
27+
deprecated_exercises=$(jq -r '
28+
[
29+
(.exercises.concept[]? | select(.status=="deprecated") | "exercises/concept/" + .slug),
30+
(.exercises.practice[]? | select(.status=="deprecated") | "exercises/practice/" + .slug)
31+
] | .[]
32+
' config.json)
33+
34+
# Check for deprecated ones
35+
for ex in $changed_exercises; do
36+
if echo "$deprecated_exercises" | grep -qx "$ex"; then
37+
echo "❌ Deprecated exercise changed: $ex"
38+
exit 1
39+
fi
40+
done
41+
42+
echo "✅ No deprecated exercises changed!"

bin/test-with-test-runner

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ docker pull exercism/java-test-runner
1212

1313
exit_code=0
1414

15+
summary_dir="exercises/build"
16+
summary_file="${summary_dir}/summary.txt"
17+
mkdir -p "$summary_dir"
18+
1519
function run_test_runner() {
1620
local slug=$1
1721
local solution_dir=$2
@@ -56,6 +60,18 @@ function verify_exercise() {
5660

5761
if [[ $(jq -r '.status' "${results_file}") != "pass" ]]; then
5862
echo "${slug}: ${implementation_file_key} solution did not pass the tests"
63+
64+
# Determine practice/slug or concept/slug
65+
local relative_path=$(echo "$dir" | sed -E 's|.*/exercises/||')
66+
67+
# Create summary.txt with header only on first failure
68+
if [ ! -f "$summary_file" ]; then
69+
echo "The following exercises have test failures or test errors:" > "$summary_file"
70+
fi
71+
72+
# Append the correct path (practice/slug or concept/slug)
73+
echo "$relative_path" >> "$summary_file"
74+
5975
exit_code=1
6076
fi
6177

concepts/chars/.meta/config.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,7 @@
33
"authors": [
44
"ystromm"
55
],
6-
"contributors": []
6+
"contributors": [
7+
"kahgoh"
8+
]
79
}

0 commit comments

Comments
 (0)