Files
tree-sitter-shellspec/.github/workflows/test.yml
Ismo Vuorinen d65c6e6ec4 refactor: enhance CI/CD workflows and apply CodeRabbit suggestions
- Convert GitHub Actions from local to inline actions for better maintainability
- Add comprehensive caching for npm dependencies, tree-sitter CLI, and build artifacts
- Fix checkout steps missing in test matrix jobs
- Apply defensive programming in test coverage validation
- Use local tree-sitter CLI via npx instead of global installation
- Update tree-sitter-cli to v0.25.0 for compatibility with tree-sitter-bash
- Add proper tree-sitter field to package.json with grammar metadata
- Fix grammar precedence for Data blocks (#| lines now have higher precedence)
- Standardize dates in memory files to September 12, 2025
- Enhance workflow robustness with dynamic workflow ID resolution
- Improve test file pattern matching and error handling

This commit addresses all CodeRabbit review suggestions and optimizes
GitHub Actions workflows for better performance and reliability.
2026-01-04 15:32:39 +02:00

248 lines
7.6 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: |
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 --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@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