mirror of
https://github.com/ivuorinen/tree-sitter-shellspec.git
synced 2026-02-02 18:46:57 +00:00
feat: implement complete tree-sitter-shellspec grammar with comprehensive testing
- Add full ShellSpec grammar extending tree-sitter-bash - Support all ShellSpec constructs: Describe, Context, It, hooks, utilities - Include Data block parsing with statements and argument styles - Add 61 comprehensive test cases covering real-world patterns - Implement optimized GitHub workflows with CI/CD automation - Configure complete development tooling (linting, formatting, pre-commit) - Add comprehensive documentation and contribution guidelines - Optimize grammar conflicts to zero warnings - Support editor integration for Neovim, VS Code, Emacs Breaking Changes: - Initial release, no previous API to break BREAKING CHANGE: Initial implementation of tree-sitter-shellspec grammar # Conflicts: # .github/workflows/codeql.yml # .github/workflows/pr-lint.yml # .pre-commit-config.yaml # Conflicts: # .github/workflows/pr-lint.yml # Conflicts: # .github/workflows/pr-lint.yml
This commit is contained in:
120
.github/actions/README.md
vendored
Normal file
120
.github/actions/README.md
vendored
Normal file
@@ -0,0 +1,120 @@
|
||||
# Composite Actions
|
||||
|
||||
This directory contains reusable composite actions to reduce duplication across workflows.
|
||||
|
||||
## Available Actions
|
||||
|
||||
### setup-node
|
||||
|
||||
Sets up Node.js with caching and installs dependencies.
|
||||
|
||||
**Inputs:**
|
||||
|
||||
- `node-version` (optional): Node.js version, defaults to '24'
|
||||
- `registry-url` (optional): NPM registry URL
|
||||
|
||||
**Usage:**
|
||||
|
||||
```yaml
|
||||
- uses: ./.github/actions/setup-node
|
||||
with:
|
||||
node-version: 22
|
||||
```
|
||||
|
||||
### setup-treesitter
|
||||
|
||||
Installs Tree-sitter CLI and generates the grammar.
|
||||
|
||||
**Usage:**
|
||||
|
||||
```yaml
|
||||
- uses: ./.github/actions/setup-treesitter
|
||||
```
|
||||
|
||||
### setup-dev
|
||||
|
||||
Complete development environment setup (combines setup-node + setup-treesitter).
|
||||
|
||||
**Inputs:**
|
||||
|
||||
- `node-version` (optional): Node.js version, defaults to '24'
|
||||
- `registry-url` (optional): NPM registry URL
|
||||
- `skip-checkout` (optional): Skip repository checkout, defaults to 'false'
|
||||
|
||||
**Usage:**
|
||||
|
||||
```yaml
|
||||
- uses: ./.github/actions/setup-dev
|
||||
with:
|
||||
node-version: 24
|
||||
skip-checkout: 'true'
|
||||
```
|
||||
|
||||
### test-grammar
|
||||
|
||||
Runs comprehensive grammar tests including parser validation.
|
||||
|
||||
**Inputs:**
|
||||
|
||||
- `skip-sample-test` (optional): Skip complex sample test, defaults to 'false'
|
||||
|
||||
**Usage:**
|
||||
|
||||
```yaml
|
||||
- uses: ./.github/actions/test-grammar
|
||||
with:
|
||||
skip-sample-test: 'true'
|
||||
```
|
||||
|
||||
### test-coverage
|
||||
|
||||
Analyzes test coverage and validates minimum requirements.
|
||||
|
||||
**Inputs:**
|
||||
|
||||
- `minimum-tests` (optional): Minimum tests required, defaults to '55'
|
||||
|
||||
**Outputs:**
|
||||
|
||||
- `total-tests`: Total number of tests found
|
||||
- `passing-tests`: Number of passing tests
|
||||
- `coverage-percent`: Test coverage percentage
|
||||
|
||||
**Usage:**
|
||||
|
||||
```yaml
|
||||
- uses: ./.github/actions/test-coverage
|
||||
with:
|
||||
minimum-tests: 60
|
||||
```
|
||||
|
||||
## Workflow Usage Examples
|
||||
|
||||
### Test Workflow (Simplified)
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
test:
|
||||
steps:
|
||||
- uses: ./.github/actions/setup-dev
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- uses: ./.github/actions/test-grammar
|
||||
```
|
||||
|
||||
### Release Workflow (Simplified)
|
||||
|
||||
```yaml
|
||||
jobs:
|
||||
test:
|
||||
steps:
|
||||
- uses: ./.github/actions/setup-dev
|
||||
- uses: ./.github/actions/test-grammar
|
||||
with:
|
||||
skip-sample-test: 'true'
|
||||
|
||||
lint:
|
||||
steps:
|
||||
- uses: ./.github/actions/setup-node
|
||||
- uses: ivuorinen/actions/pr-lint@latest
|
||||
```
|
||||
38
.github/actions/setup-dev/action.yml
vendored
Normal file
38
.github/actions/setup-dev/action.yml
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
---
|
||||
name: "Setup Development Environment"
|
||||
description: "Complete setup for tree-sitter-shellspec development including Node.js and Tree-sitter"
|
||||
|
||||
inputs:
|
||||
node-version:
|
||||
description: "Node.js version to setup"
|
||||
required: false
|
||||
default: "24"
|
||||
registry-url:
|
||||
description: "NPM registry URL"
|
||||
required: false
|
||||
default: ""
|
||||
skip-checkout:
|
||||
description: "Skip repository checkout (if already done)"
|
||||
required: false
|
||||
default: "false"
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
if: inputs.skip-checkout != 'true'
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
|
||||
- name: Setup Node.js ${{ inputs.node-version }}
|
||||
uses: actions/setup-node@7c12f8017d5436eb855f1ed4399f037a36fbd9e8 # v5.2.1
|
||||
with:
|
||||
node-version: ${{ inputs.node-version }}
|
||||
cache: npm
|
||||
registry-url: ${{ inputs.registry-url }}
|
||||
|
||||
- name: Install Dependencies
|
||||
run: npm ci || { echo "❌ npm install failed" && npm install }
|
||||
shell: bash
|
||||
|
||||
- name: Setup Tree-sitter Environment
|
||||
uses: ./.github/actions/setup-treesitter
|
||||
30
.github/actions/setup-node/action.yml
vendored
Normal file
30
.github/actions/setup-node/action.yml
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
---
|
||||
name: "Setup Node.js Environment"
|
||||
description: "Sets up Node.js with caching and installs dependencies"
|
||||
|
||||
inputs:
|
||||
node-version:
|
||||
description: "Node.js version to setup"
|
||||
required: false
|
||||
default: "24"
|
||||
registry-url:
|
||||
description: "NPM registry URL"
|
||||
required: false
|
||||
default: ""
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
|
||||
- name: Setup Node.js ${{ inputs.node-version }}
|
||||
uses: actions/setup-node@7c12f8017d5436eb855f1ed4399f037a36fbd9e8 # v5.2.1
|
||||
with:
|
||||
node-version: ${{ inputs.node-version }}
|
||||
cache: npm
|
||||
registry-url: ${{ inputs.registry-url }}
|
||||
|
||||
- name: Install Dependencies
|
||||
run: npm ci || { echo "❌ npm install failed" && npm install }
|
||||
shell: bash
|
||||
14
.github/actions/setup-treesitter/action.yml
vendored
Normal file
14
.github/actions/setup-treesitter/action.yml
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
---
|
||||
name: "Setup Tree-sitter Environment"
|
||||
description: "Installs Tree-sitter CLI and generates grammar"
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Install Tree-sitter CLI
|
||||
run: npm install -g tree-sitter-cli
|
||||
shell: bash
|
||||
|
||||
- name: Generate Grammar
|
||||
run: npm run generate
|
||||
shell: bash
|
||||
71
.github/actions/test-coverage/action.yml
vendored
Normal file
71
.github/actions/test-coverage/action.yml
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
---
|
||||
name: "Test Coverage Analysis"
|
||||
description: "Analyzes test coverage and generates coverage report"
|
||||
|
||||
inputs:
|
||||
minimum-tests:
|
||||
description: "Minimum number of tests required"
|
||||
required: false
|
||||
default: "55"
|
||||
|
||||
outputs:
|
||||
total-tests:
|
||||
description: "Total number of tests found"
|
||||
value: ${{ steps.coverage.outputs.total-tests }}
|
||||
passing-tests:
|
||||
description: "Number of passing tests"
|
||||
value: ${{ steps.coverage.outputs.passing-tests }}
|
||||
coverage-percent:
|
||||
description: "Test coverage percentage"
|
||||
value: ${{ steps.coverage.outputs.coverage-percent }}
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Test Coverage Analysis
|
||||
id: coverage
|
||||
run: |
|
||||
echo "## Test Coverage Report" > coverage_report.md
|
||||
echo "" >> coverage_report.md
|
||||
|
||||
# Run tests and capture output
|
||||
TEST_OUTPUT=$(npm test 2>&1)
|
||||
TOTAL_TESTS=$(echo "$TEST_OUTPUT" | grep -E "^\s+[0-9]+\." | wc -l)
|
||||
PASSING_TESTS=$(echo "$TEST_OUTPUT" | grep -E "^\s+[0-9]+\. ✓" | wc -l)
|
||||
FAILING_TESTS=$(echo "$TEST_OUTPUT" | grep -E "^\s+[0-9]+\. ✗" | wc -l)
|
||||
|
||||
echo "- **Total Tests:** $TOTAL_TESTS" >> coverage_report.md
|
||||
echo "- **Passing:** $PASSING_TESTS ✅" >> coverage_report.md
|
||||
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 "" >> coverage_report.md
|
||||
echo "### Test Files" >> coverage_report.md
|
||||
echo "$TEST_OUTPUT" | grep -E "^\s+[a-z_]+:" | sed 's/^/- /' >> coverage_report.md
|
||||
|
||||
cat coverage_report.md
|
||||
|
||||
# Set outputs
|
||||
echo "total-tests=$TOTAL_TESTS" >> $GITHUB_OUTPUT
|
||||
echo "passing-tests=$PASSING_TESTS" >> $GITHUB_OUTPUT
|
||||
echo "coverage-percent=$COVERAGE_PERCENT" >> $GITHUB_OUTPUT
|
||||
|
||||
# Validate test coverage requirements
|
||||
if [ $TOTAL_TESTS -lt ${{ inputs.minimum-tests }} ]; then
|
||||
echo "❌ Expected at least ${{ inputs.minimum-tests }} tests, found $TOTAL_TESTS"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ $FAILING_TESTS -gt 0 ]; then
|
||||
echo "❌ Found $FAILING_TESTS failing tests"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✅ Test coverage is acceptable: $PASSING_TESTS/$TOTAL_TESTS tests passing ($COVERAGE_PERCENT%)"
|
||||
shell: bash
|
||||
77
.github/actions/test-grammar/action.yml
vendored
Normal file
77
.github/actions/test-grammar/action.yml
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
---
|
||||
name: "Test Tree-sitter Grammar"
|
||||
description: "Runs comprehensive grammar tests including parser validation"
|
||||
|
||||
inputs:
|
||||
skip-sample-test:
|
||||
description: "Skip the sample ShellSpec code test"
|
||||
required: false
|
||||
default: "false"
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Run Tests
|
||||
run: npm test
|
||||
shell: bash
|
||||
|
||||
- name: Build Parser
|
||||
run: npm run build
|
||||
shell: bash
|
||||
|
||||
- name: Test Parser with Sample Code
|
||||
if: inputs.skip-sample-test != 'true'
|
||||
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 test_sample.shellspec --quiet || {
|
||||
echo "❌ Parser failed on sample ShellSpec code"
|
||||
exit 1
|
||||
}
|
||||
echo "✅ Parser successfully handled sample code"
|
||||
shell: bash
|
||||
|
||||
- name: Validate Parser (Simple)
|
||||
if: inputs.skip-sample-test == 'true'
|
||||
run: |
|
||||
echo "Describe 'test' It 'works' End End" | tree-sitter parse --language=shellspec || {
|
||||
echo "❌ Parser validation failed"
|
||||
exit 1
|
||||
}
|
||||
echo "✅ Parser validation successful"
|
||||
shell: bash
|
||||
Reference in New Issue
Block a user