Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 52 additions & 20 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -188,8 +188,10 @@ jobs:
if: matrix.test_commit_records
run: yarn test-upsert-comment

# The format check gives the same result everywhere; it runs on Linux
# only, where it is fastest.
- name: Run tests
run: node scripts/test.js -all
run: node scripts/test.js ${{ runner.os == 'Linux' && '-all' || '-ounit -mocha -build -docstrings' }}

- name: Check for diffs in tests folder
run: git diff --ignore-cr-at-eol --exit-code tests
Expand Down Expand Up @@ -393,50 +395,80 @@ jobs:

# Checks that the website builds with the generated API docs. These
# steps stay in this job rather than in one that needs build-compiler,
# which would wait for the slowest platform before starting.
- name: Checkout rescript-lang.org
# which would wait for the slowest platform before starting. The build
# depends only on the docs and the website commit, so an empty cache
# entry keyed on both records each pair that built, and a pull request
# whose docs match an earlier build skips it.
- name: Website build key
id: website-build-key
if: ${{ matrix.generate_api_docs }}
env:
WEBSITE_BRANCH: ${{ steps.api-docs-plan.outputs.website-branch }}
run: |
sha=$(git ls-remote https://github.com/rescript-lang/rescript-lang.org.git "refs/heads/$WEBSITE_BRANCH" | cut -f1)
if [ -z "$sha" ]; then
echo "::error::The website has no branch $WEBSITE_BRANCH"
exit 1
fi
echo "sha=$sha" >> "$GITHUB_OUTPUT"
echo "value=website-build-v1-$sha-${{ hashFiles('scripts/res/apiDocs/**') }}" >> "$GITHUB_OUTPUT"
shell: bash

- name: Look up website build
id: website-build
if: ${{ matrix.generate_api_docs }}
uses: actions/cache/restore@v6
with:
path: tmp/website-build
key: ${{ steps.website-build-key.outputs.value }}
lookup-only: true

- name: Checkout rescript-lang.org
if: ${{ matrix.generate_api_docs && steps.website-build.outputs.cache-hit != 'true' }}
uses: actions/checkout@v7
with:
repository: rescript-lang/rescript-lang.org
ref: ${{ steps.api-docs-plan.outputs.website-branch }}
ref: ${{ steps.website-build-key.outputs.sha }}
path: rescript-lang.org

- name: Check for API docs changes
id: api-docs-diff
if: ${{ matrix.generate_api_docs }}
run: |
cp -R scripts/res/apiDocs/. rescript-lang.org/data/api/
git -C rescript-lang.org status
if [[ -z "$(git -C rescript-lang.org status --porcelain)" ]]; then
echo "changed=false" >> "$GITHUB_OUTPUT"
else
echo "changed=true" >> "$GITHUB_OUTPUT"
fi
shell: bash

# The website is checked out inside this repository, so its Yarn also
# reads this repository's .yarnrc.yml and rejects the settings it does
# not know yet. The steps that need this config are done.
- name: Hide the compiler's Yarn config from the website
if: ${{ matrix.generate_api_docs && steps.api-docs-diff.outputs.changed == 'true' }}
if: ${{ matrix.generate_api_docs && steps.website-build.outputs.cache-hit != 'true' }}
run: mv .yarnrc.yml "$RUNNER_TEMP/rescript.yarnrc.yml"
shell: bash

- name: Use Node.js for website
if: ${{ matrix.generate_api_docs && steps.api-docs-diff.outputs.changed == 'true' }}
if: ${{ matrix.generate_api_docs && steps.website-build.outputs.cache-hit != 'true' }}
uses: actions/setup-node@v7
with:
cache: yarn
cache-dependency-path: rescript-lang.org/yarn.lock
node-version-file: rescript-lang.org/.node-version

- name: Build website with the API docs
if: ${{ matrix.generate_api_docs && steps.api-docs-diff.outputs.changed == 'true' }}
if: ${{ matrix.generate_api_docs && steps.website-build.outputs.cache-hit != 'true' }}
run: |
cp -R ../scripts/res/apiDocs/. data/api/
yarn
yarn build
working-directory: rescript-lang.org
shell: bash

- name: Record website build
if: ${{ matrix.generate_api_docs && steps.website-build.outputs.cache-hit != 'true' }}
run: mkdir -p tmp/website-build && echo "$KEY" > tmp/website-build/key
env:
KEY: ${{ steps.website-build-key.outputs.value }}
shell: bash

- name: Save website build record
if: ${{ matrix.generate_api_docs && steps.website-build.outputs.cache-hit != 'true' }}
uses: actions/cache/save@v6
with:
path: tmp/website-build
key: ${{ steps.website-build-key.outputs.value }}

# Compares the words the compiler allocates on fixed inputs, and the
# instructions it executes on some of them, with the base branch
Expand Down
88 changes: 29 additions & 59 deletions rewatch/tests/utils.sh
Original file line number Diff line number Diff line change
Expand Up @@ -60,14 +60,21 @@ replace() {
fi
}

wait_for_pid_gone() {
local pid="$1"; local timeout
timeout=${2:-20}
while process_is_running "$pid" && [ "$timeout" -gt 0 ]; do
sleep 1
timeout=$((timeout - 1))
# Runs a command every 0.1 seconds until it succeeds or the timeout in
# seconds (the first argument) has passed. A one-second interval made every
# wait in the suite take up to a second longer than needed.
poll() {
local deadline=$((SECONDS + $1)); shift
until "$@"; do
[ "$SECONDS" -lt "$deadline" ] || return 1
sleep 0.1
done
! process_is_running "$pid"
}

process_is_gone() { ! process_is_running "$1"; }

wait_for_pid_gone() {
poll "${2:-20}" process_is_gone "$1"
}

exit_watcher() {
Expand Down Expand Up @@ -116,62 +123,25 @@ clear_locks() {
rm -f lib/rescript/watch.lock lib/rescript/build.lock
}

wait_for_file() {
local file="$1"; local timeout
timeout=${2:-60}
while [ "$timeout" -gt 0 ]; do
[ -f "$file" ] && return 0
sleep 1
timeout=$((timeout - 1))
done
return 1
}
file_exists() { [ -f "$1" ]; }
file_is_gone() { [ ! -f "$1" ]; }
file_has_pattern() { grep -q "$2" "$1" 2>/dev/null; }

wait_for_pattern() {
local file="$1"; local pattern="$2"; local timeout
timeout=${3:-60}
while [ "$timeout" -gt 0 ]; do
grep -q "$pattern" "$file" 2>/dev/null && return 0
sleep 1
timeout=$((timeout - 1))
done
return 1
file_lacks_pattern() {
[ -f "$1" ] && ! grep -q "$2" "$1" 2>/dev/null
}

wait_for_pattern_count() {
local file="$1"; local pattern="$2"; local expected="$3"; local timeout
timeout=${4:-60}
while [ "$timeout" -gt 0 ]; do
local current_count
current_count=$(grep -c "$pattern" "$file" 2>/dev/null || true)
current_count=${current_count:-0}
[ "$current_count" -ge "$expected" ] && return 0
sleep 1
timeout=$((timeout - 1))
done
return 1
file_has_pattern_count() {
local current_count
current_count=$(grep -c "$2" "$1" 2>/dev/null || true)
[ "${current_count:-0}" -ge "$3" ]
}

wait_for_pattern_gone() {
local file="$1"; local pattern="$2"; local timeout
timeout=${3:-60}
while [ "$timeout" -gt 0 ]; do
if [ -f "$file" ] && ! grep -q "$pattern" "$file" 2>/dev/null; then
return 0
fi
sleep 1
timeout=$((timeout - 1))
done
return 1
}
wait_for_file() { poll "${2:-60}" file_exists "$1"; }
wait_for_file_gone() { poll "${2:-60}" file_is_gone "$1"; }
wait_for_pattern() { poll "${3:-60}" file_has_pattern "$1" "$2"; }
wait_for_pattern_gone() { poll "${3:-60}" file_lacks_pattern "$1" "$2"; }

wait_for_file_gone() {
local file="$1"; local timeout
timeout=${2:-60}
while [ "$timeout" -gt 0 ]; do
[ ! -f "$file" ] && return 0
sleep 1
timeout=$((timeout - 1))
done
return 1
wait_for_pattern_count() {
poll "${4:-60}" file_has_pattern_count "$1" "$2" "$3"
}
15 changes: 5 additions & 10 deletions rewatch/tests/watch/02-watch-warnings-persist-atomic-save.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,12 @@ else
exit 1
fi

completed_log_changed() {
[ -f "$1" ] && ! cmp -s "$1" "$2" && grep -q "#Done(" "$1" 2>/dev/null
}

wait_for_changed_completed_log() {
local file="$1"; local baseline="$2"; local timeout
timeout=${3:-60}
while [ "$timeout" -gt 0 ]; do
if [ -f "$file" ] && ! cmp -s "$file" "$baseline" && grep -q "#Done(" "$file" 2>/dev/null; then
return 0
fi
sleep 1
timeout=$((timeout - 1))
done
return 1
poll "${3:-60}" completed_log_changed "$1" "$2"
}

COMPILER_LOG="./packages/watch-warnings/lib/rescript/.compiler.log"
Expand Down
25 changes: 9 additions & 16 deletions rewatch/tests/watch/04-watch-config-change.sh
Original file line number Diff line number Diff line change
Expand Up @@ -42,17 +42,12 @@ wait_for_next_build() {
"$completed_builds" 30
}

tracked_outputs_exist() {
[ -z "$(git ls-files --deleted -- '*.mjs')" ]
}

wait_for_tracked_outputs() {
local timeout
timeout=60
while [ "$timeout" -gt 0 ]; do
if [ -z "$(git ls-files --deleted -- '*.mjs')" ]; then
return 0
fi
sleep 1
timeout=$((timeout - 1))
done
return 1
poll 60 tracked_outputs_exist
}

# Change the suffix in rescript.json (same approach as suffix test)
Expand Down Expand Up @@ -118,12 +113,10 @@ else
fi

# The rebuild after the restore also removes the outputs with the new suffix.
timeout=30
while [ "$timeout" -gt 0 ] && [ -n "$(find . -name '*.res.mjs' -print -quit)" ]; do
sleep 1
timeout=$((timeout - 1))
done
if [ -n "$(find . -name '*.res.mjs' -print -quit)" ]; then
suffixed_outputs_gone() {
[ -z "$(find . -name '*.res.mjs' -print -quit)" ]
}
if ! poll 30 suffixed_outputs_gone; then
error "Outputs with the restored configuration's previous suffix were not removed"
find . -name '*.res.mjs'
git restore --worktree -- ./src/Test.res
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,18 +44,13 @@ REWATCH_COMPILER_DOMAINS=1 "$REWATCH_EXECUTABLE" watch > rewatch.log 2>&1 &
watch_pid=$!
compiler_log=lib/rescript/.compiler.log

compiler_log_changed() {
[ -f "$compiler_log" ] && ! cmp -s "$compiler_log" "$1" &&
grep -q '#Done(' "$compiler_log"
}

wait_for_changed_compiler_log() {
local baseline="$1"; local timeout
timeout=60
while [ "$timeout" -gt 0 ]; do
if [ -f "$compiler_log" ] && ! cmp -s "$compiler_log" "$baseline" &&
grep -q '#Done(' "$compiler_log"; then
return 0
fi
sleep 1
timeout=$((timeout - 1))
done
return 1
poll 60 compiler_log_changed "$1"
}

if ! wait_for_pattern_count rewatch.log "Finished .*compilation" 1 60; then
Expand Down
27 changes: 10 additions & 17 deletions rewatch/tests/watch/08-watch-overlapping-source-removed.sh
Original file line number Diff line number Diff line change
Expand Up @@ -42,18 +42,13 @@ retained_output() {
rewatch_bg watch > rewatch.log 2>&1 &
success "Watcher Started"

retained_output_has() {
output=$(retained_output)
[ -n "$output" ] && grep -q "$1" "$output"
}

wait_for_retained_value() {
local value=$1
local timeout=30
while [ "$timeout" -gt 0 ]; do
output=$(retained_output)
if [ -n "$output" ] && grep -q "$value" "$output"; then
return 0
fi
sleep 1
timeout=$((timeout - 1))
done
return 1
poll 30 retained_output_has "$1"
}

if ! wait_for_retained_value "= 1"; then
Expand All @@ -70,12 +65,10 @@ success "Initial build completed"
# watched on its own
mkdir "$RETAINED/nested"
echo 'let value = 1' > "$RETAINED/nested/Nested.res"
timeout=30
until [ -n "$(find "$RETAINED/nested" -name 'Nested.*js')" ] || [ "$timeout" -le 0 ]; do
sleep 1
timeout=$((timeout - 1))
done
if [ -n "$(find "$RETAINED/nested" -name 'Nested.*js')" ]; then
nested_output_exists() {
[ -n "$(find "$RETAINED/nested" -name 'Nested.*js')" ]
}
if poll 30 nested_output_exists; then
success "A folder created inside the retained folder is watched"
else
error "A folder created inside the retained folder is not watched"
Expand Down
Loading