Files
tree-sitter-shellspec/.github/workflows/test.yml

252 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@dfa6ed13c88fe79b56c4ffc79a42db2e8d2b15a5 # v4.2.0
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@dfa6ed13c88fe79b56c4ffc79a42db2e8d2b15a5 # v4.2.0
id: cache-tree-sitter
with:
path: ~/.npm/_npx
key: ${{ runner.os }}-tree-sitter-cli-${{ hashFiles('package.json') }}
- name: Install Tree-sitter CLI
run: npm install -g tree-sitter-cli
shell: bash
- name: Cache Generated Grammar
uses: actions/cache@dfa6ed13c88fe79b56c4ffc79a42db2e8d2b15a5 # v4.2.0
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@dfa6ed13c88fe79b56c4ffc79a42db2e8d2b15a5 # v4.2.0
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: |
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
tree-sitter parse --language=shellspec 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@dfa6ed13c88fe79b56c4ffc79a42db2e8d2b15a5 # v4.2.0
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@dfa6ed13c88fe79b56c4ffc79a42db2e8d2b15a5 # v4.2.0
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