Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[4/?] Add ability to run code examples in the playground: Get pony snippets tested with ponyc at CI time #550

Draft
wants to merge 13 commits into
base: main
Choose a base branch
from
Draft
75 changes: 75 additions & 0 deletions .github/workflows/check-code-samples.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
cd ./code-samples/
files=$(ls | wc -l)
echo "Check $files files …"
failedFiles=()
notRunnable=0
i=0
for file in *.pony; do # actors-sequential.pony
((i++))
percentage=$(((i*100)/files))
echo -e "#$i Test $file … ($i/$files \u2192 $percentage %)"
contents=$(cat "$file") # code-samples/
#echo "contents: $contents"
regex='^"""\n(?<line>^(?<key>[a-z_]+):\s?(?<value>.*?)$\n)+"""' # TODO: Get frontmatter from AST
regex='^"""\n(.*)\n"""'
expectations=$(jq --arg file "${file}" ".[\"$file\"]" ../code-samples.json) # -r
#echo "Expectations for $file $expectations"
isRunnable=$(echo "$expectations" | jq '.runnable')
if ! [ -z "$expectations" ] && ! $isRunnable; then
echo -e "\u2139\uFE0F File not runnable. Skip"
((notRunnable++))
continue
fi
expectedStdout=$(echo "$expectations" | jq '.stdout')
expectedStderr=$(echo "$expectations" | jq '.stderr')
expectedExitcode=$(echo "$expectations" | jq '.exitcode')
#echo "stdout for $file: "
#echo "$contents" | grep -e $regex
if [ $(echo "$contents" | grep -qe $regex) ]; then # TODO: fix regex
frontmatter="${BASH_REMATCH[0]}"
readarray -d "\n" -t lines <<< frontmatter
echo "Expectations 1: ${lines[0]}"
fi
if [[ "$contents" =~ $regex ]]; then
frontmatter="${BASH_REMATCH[0]}"
readarray -d "\n" -t lines <<< frontmatter
echo "Expectations: ${lines[0]}"
fi
encoded=$(sed -E -e ':a;N;$!ba;s/\r\n|\r|\n/\\n/g' "$file") #code-samples/
encoded=${encoded//\"/\\\"}
encoded=${encoded// /\\t}
json="{\"code\": \"$encoded\", \"separate_output\": true, \"color\": true, \"branch\": \"release\"}"
#echo "Send $json…"
response=$(curl -s --header "Content-Type: application/json" \
--request POST \
--data "$json" \
"https://playground.ponylang.io/evaluate.json")
Comment on lines +43 to +46
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than calling out to the playground to run these, we should use ponyc directly here. We don't want to flood the playground when running these tests, and we don't want the uptime of the playground to affect these tests.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, I implemented it in a way I'm familiar, since nobody replied to "I still need to figure out, how that might work 🤔 If there's someone else who would take this on, I wouldn't be mad 😅" in #340. I can try doing it via ponyc but how it will turn out is up to be shown.

success=$(echo "$response" | jq '.success')
actualStdout=$(echo "$response" | jq '.stdout')
actualStderr=$(echo "$response" | jq '.stderr')
if $success && ! [ -z "$expectations" ] && [ "$expectedExitcode" = "0" ] && [ "$actualStdout" = "$expectedStdout" ]; then
echo -e "\e[1;32m\u2705 File fulfilled expectations\e[0m"
elif ! $success && ! [ -z "$expectations" ] && [ "$expectedExitcode" = "1" ] && [ "$actualStderr" = "$expectedStderr" ]; then
echo -e "\e[1;32m\u2705 File fulfilled expectations\e[0m"
else
failedFiles+=(file)
echo -e "\e[1;31m\u274C File didn't fulfill expectations\e[0m"
if [ "$expectedExitcode" = "0" ]; then
echo "Success = true (actual: $success), stdout = $expectedStdout (actual: ${actualStdout-null})"
else
echo "Success = false (actual: $success), stderr = $expectedStderr (actual: ${actualStderr-null})"
fi
echo $response
echo $expectations
echo $expectedExitcode
fi
#break
done
runnableFiles=$((files-notRunnable))
if [ "${#failedFiles[@]}" != 0 ]; then
echo -e "\e[1;31m💥 ${#failedFiles[@]}/$runnableFiles file(s) ($files total) had errors\e[0m"
exit 1
else
echo -e "\e[1;32m🎉 All $files files ($runnableFiles runnable) were checked successfully\e[0m"
exit 0
fi
17 changes: 17 additions & 0 deletions .github/workflows/check-code-samples.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
name: Check code samples

on:
pull_request:
push:

jobs:
check-code-samples:
name: Check code samples
runs-on: ubuntu-latest
steps:
- name: Check out repository code
uses: actions/checkout@v4
- name: Install jq
run: curl -sS https://webi.sh/jq | bash
- name: Check code samples
run: ${GITHUB_WORKSPACE}/.github/workflows/check-code-samples.sh
23 changes: 23 additions & 0 deletions code-samples.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"actors-sequential.pony": {
"runnable": true,
"stdout": "This is printed first\nThis is printed last\n",
"stderr": null,
"exitcode": 0
},
"traits-and-interfaces-private-methods.pony": {
"runnable": true,
"stdout": null,
"stderr": "interfaces can't have private methods, only traits can\n",
"exitcode": 1
},
"actors-behaviors.pony": {
"runnable": false
},
"appendices-examples-access-command-line-arguments.pony": {
"runnable": true,
"stdout": "This is printed first\nThis is printed last\n",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We shouldn't need to test stdout of running the examples - we just need to prove that an example successfully compiles (or fails to compile with a particular message in stderr). We don't need to run the examples at all - just compile them.

Copy link
Collaborator Author

@shaedrich shaedrich Jun 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the point of a snippet if it does something but we don't even know if it illustrates what the chapter talks about? It just happens to have a few buzzwords in it. Seeing them compile successfully is nice but very surface-level to me. There actually have been examples that failed running in the playground despite it successfully running was to be expected because nobody bothered to check it in the playground before. Nice letting users of the tutorial twist in the wind with compilable but unrunnable code—yay! 🎉

"stderr": null,
"exitcode": 0
}
}
7 changes: 7 additions & 0 deletions code-samples/actors-sequential.pony
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
"""
description: "Execution order of actor behaviors"
stdout: This is printed first\nThis is printed last\n
stderr:
exitcode: 0
"""

actor Main
new create(env: Env) =>
call_me_later(env)
Expand Down
Loading