Files
tree-sitter-shellspec/.github/workflows/test.yml
Ismo Vuorinen c5334da82f fix(ci): ensure parser is built before testing in GitHub workflows
- Add explicit parser build step before sample code testing
- Remove --scope parameter that requires parser to be compiled first
- Fix tree-sitter CLI v0.25.0 compatibility issue in CI environment

The issue was that tree-sitter CLI v0.25.0 requires the parser to be
compiled before it can recognize custom language scopes. This fix
ensures the parser is always built before attempting to parse test files,
resolving the 'Unknown scope' error in GitHub Actions.
2026-01-04 15:32:40 +02:00

251 lines
7.7 KiB
YAML

---
# yaml-language-server: $schema=https://www.schemastore.org/github-workflow.json
name: CI
on:
push:
branches: [main, master]
pull_request:
branches: [main, master]
merge_group:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions: read-all
jobs:
test:
name: 🧪 Test Suite
runs-on: ubuntu-latest
timeout-minutes: 15
strategy:
matrix:
node-version: [22, 24]
fail-fast: false
steps:
- name: Checkout Repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@7c12f8017d5436eb855f1ed4399f037a36fbd9e8 # v5.2.1
with:
node-version: ${{ matrix.node-version }}
- name: Cache Node.js dependencies
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
id: cache-npm
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ matrix.node-version }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-${{ matrix.node-version }}-
${{ runner.os }}-node-
- name: Install Dependencies
run: npm ci || { echo "❌ npm install failed"; npm install; }
shell: bash
- name: Cache Tree-sitter CLI
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
id: cache-tree-sitter
with:
path: ~/.npm/_npx
key: ${{ runner.os }}-tree-sitter-cli-${{ hashFiles('package.json') }}
- name: Cache Generated Grammar
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
id: cache-grammar
with:
path: |
src/parser.c
src/tree_sitter/
binding.gyp
key: ${{ runner.os }}-grammar-${{ hashFiles('grammar.js', 'package.json') }}
- name: Generate Grammar
if: steps.cache-grammar.outputs.cache-hit != 'true'
run: npm run generate
shell: bash
- name: Cache Built Parser
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
id: cache-parser
with:
path: |
build/
node_modules/
key: ${{ runner.os }}-parser-${{ matrix.node-version }}-${{ hashFiles('src/parser.c', 'binding.gyp', 'package.json') }}
- name: Build Parser
if: steps.cache-parser.outputs.cache-hit != 'true'
run: npm run build
shell: bash
- name: Test Parser with Sample Code
run: |
# Ensure parser is built
npm run build
cat << 'EOF' > test_sample.shellspec
#!/usr/bin/env shellspec
Describe 'Calculator'
Include ./lib/calculator.sh
Before 'setup_calculator'
After 'cleanup_calculator'
Context 'when adding numbers'
It 'adds two positive numbers'
When call add 2 3
The output should eq 5
End
It 'handles zero'
When call add 0 5
The output should eq 5
End
End
Context 'when input is invalid'
Skip if "validation not implemented" ! command -v validate
It 'handles empty input'
When call add "" ""
The status should be failure
End
End
End
It 'works without describe block'
When call echo "test"
The output should eq "test"
End
EOF
npx tree-sitter parse test_sample.shellspec --quiet || {
echo "❌ Parser failed on sample ShellSpec code"
exit 1
}
echo "✅ Parser successfully handled sample code"
shell: bash
lint:
name: 🧹 Code Quality
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Checkout Repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Node.js 24
uses: actions/setup-node@7c12f8017d5436eb855f1ed4399f037a36fbd9e8 # v5.2.1
with:
node-version: 24
- name: Cache Node.js dependencies
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
with:
path: ~/.npm
key: ${{ runner.os }}-node-24-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-24-
${{ runner.os }}-node-
- name: Install Dependencies
run: npm ci || { echo "❌ npm install failed"; npm install; }
shell: bash
- name: 🧹 Run Linter
uses: ivuorinen/actions/pr-lint@22e6add79fabcca4bf5761452a51e4fa0207e155 # 25.9.8
coverage:
name: 📊 Test Coverage
runs-on: ubuntu-latest
timeout-minutes: 15
needs: test
steps:
- name: Checkout Repository
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
- name: Setup Node.js 24
uses: actions/setup-node@7c12f8017d5436eb855f1ed4399f037a36fbd9e8 # v5.2.1
with:
node-version: 24
- name: Cache Node.js dependencies
uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
with:
path: ~/.npm
key: ${{ runner.os }}-node-24-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-24-
${{ runner.os }}-node-
- name: Install Dependencies
run: npm ci || { echo "❌ npm install failed"; npm install; }
- name: Test Coverage Analysis
id: coverage
run: |
echo "## Test Coverage Report" > coverage_report.md
echo "" >> coverage_report.md
# Run tests and capture output with exit code
set +e # Don't exit on test failure
TEST_OUTPUT=$(npm test 2>&1)
TEST_EXIT=$?
set -e # Re-enable exit on error
TOTAL_TESTS=$(echo "$TEST_OUTPUT" | grep -cE "^\s+[0-9]+\." || echo "0")
PASSING_TESTS=$(echo "$TEST_OUTPUT" | grep -cE "^\s+[0-9]+\. ✓" || echo "0")
FAILING_TESTS=$(echo "$TEST_OUTPUT" | grep -cE "^\s+[0-9]+\. ✗" || echo "0")
{
echo "- **Total Tests:** $TOTAL_TESTS"
echo "- **Passing:** $PASSING_TESTS ✅"
echo "- **Failing:** $FAILING_TESTS ❌"
} >> coverage_report.md
if [ "$TOTAL_TESTS" -gt 0 ]; then
COVERAGE_PERCENT=$(( (PASSING_TESTS * 100) / TOTAL_TESTS ))
echo "- **Coverage:** $COVERAGE_PERCENT%" >> coverage_report.md
else
COVERAGE_PERCENT=0
fi
{
echo ""
echo "### Test Files"
} >> coverage_report.md
echo "$TEST_OUTPUT" | grep -E "^[[:space:]]+[A-Za-z0-9._/\\-]+:" | sed 's/^/- /' >> coverage_report.md
cat coverage_report.md
# Set outputs
{
echo "total-tests=$TOTAL_TESTS"
echo "passing-tests=$PASSING_TESTS"
echo "coverage-percent=$COVERAGE_PERCENT"
} >> "$GITHUB_OUTPUT"
# Validate test coverage requirements
if [ "${TOTAL_TESTS:-0}" -lt 55 ]; then
echo "❌ Expected at least 55 tests, found ${TOTAL_TESTS:-0}"
exit 1
fi
if [ "${FAILING_TESTS:-0}" -gt 0 ] || [ "$TEST_EXIT" -ne 0 ]; then
echo "❌ Found ${FAILING_TESTS:-0} failing tests or test runner failed (exit code: $TEST_EXIT)"
exit 1
fi
echo "✅ Test coverage is acceptable: $PASSING_TESTS/$TOTAL_TESTS tests passing ($COVERAGE_PERCENT%)"
shell: bash