diff --git a/.gitea/workflows/python/code-quality.yml b/.gitea/workflows/python/code-quality.yml
index 07aa324..302de3a 100644
--- a/.gitea/workflows/python/code-quality.yml
+++ b/.gitea/workflows/python/code-quality.yml
@@ -1,6 +1,7 @@
+---
name: Python Code Quality Pipeline
-on:
+"on":
workflow_call:
inputs:
python-version:
@@ -36,7 +37,7 @@ jobs:
defaults:
run:
working-directory: ${{ inputs.working-directory }}
-
+
steps:
- name: Checkout code
uses: actions/checkout@v4
@@ -71,4 +72,8 @@ jobs:
- name: Pyupgrade check
if: ${{ !inputs.skip-pyupgrade }}
- run: uv run pyupgrade --py312-plus $(git ls-files '*.py') && git diff --exit-code
\ No newline at end of file
+ run: |
+ echo "Running pyupgrade..."
+ uv run pyupgrade --py312-plus $(git ls-files '*.py')
+ echo "Checking for changes..."
+ git diff --exit-code
diff --git a/.gitea/workflows/python/pytest.yml b/.gitea/workflows/python/pytest.yml
index b1174bf..347c98a 100644
--- a/.gitea/workflows/python/pytest.yml
+++ b/.gitea/workflows/python/pytest.yml
@@ -1,6 +1,7 @@
+---
name: Python Test Pipeline
-on:
+"on":
workflow_call:
inputs:
python-version:
@@ -49,7 +50,7 @@ jobs:
defaults:
run:
working-directory: ${{ inputs.working-directory }}
-
+
steps:
- name: Checkout code
uses: actions/checkout@v4
@@ -77,13 +78,20 @@ jobs:
PYTHONPATH: .
run: |
if [ -n "${{ inputs.coverage-package }}" ]; then
- uv run pytest --cov=${{ inputs.coverage-package }} --cov-report=term-missing ${{ inputs.pytest-args }} > coverage.txt
+ uv run pytest --cov=${{ inputs.coverage-package }} \
+ --cov-report=term-missing ${{ inputs.pytest-args }} > coverage.txt
else
uv run pytest ${{ inputs.pytest-args }}
fi
- name: Post coverage summary to PR
- if: ${{ !inputs.skip-coverage-comment && inputs.coverage-package != '' && github.event_name == 'pull_request' && inputs.api-url != '' }}
+ if: >-
+ ${{
+ !inputs.skip-coverage-comment &&
+ inputs.coverage-package != '' &&
+ github.event_name == 'pull_request' &&
+ inputs.api-url != ''
+ }}
env:
API_URL: ${{ inputs.api-url }}
REPO_OWNER: ${{ github.repository_owner }}
@@ -94,7 +102,9 @@ jobs:
if [ -f coverage.txt ]; then
COVERAGE=$(cat coverage.txt)
COMMENT_BODY="**Test Coverage Report:**\n\`\`\`\n$COVERAGE\n\`\`\`"
- curl -s -X POST "$API_URL/repos/$REPO_OWNER/$REPO_NAME/issues/$PR_NUMBER/comments" \
+ API_ENDPOINT="$API_URL/repos/$REPO_OWNER/$REPO_NAME/issues/$PR_NUMBER/comments"
+ curl -s -X POST \
+ "$API_ENDPOINT" \
-H "Authorization: token $CI_RUNNER_TOKEN" \
-H "Content-Type: application/json" \
-d "{\"body\": \"$COMMENT_BODY\"}"
diff --git a/.gitea/workflows/test-templates.yml b/.gitea/workflows/test-templates.yml
index e35d2ec..16dc234 100644
--- a/.gitea/workflows/test-templates.yml
+++ b/.gitea/workflows/test-templates.yml
@@ -1,6 +1,7 @@
+---
name: Test CI Templates
-on:
+"on":
push:
branches: [main]
pull_request:
@@ -14,24 +15,29 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v4
-
+
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"
-
+
- name: Install yamllint
run: pip install yamllint
-
+
- name: Validate YAML syntax
run: |
echo "Validating workflow YAML syntax..."
find .gitea/workflows -name "*.yml" -exec yamllint {} \;
-
+
- name: Check workflow structure
run: |
echo "Checking workflow structure..."
for file in .gitea/workflows/**/*.yml; do
+ # Skip the test file itself
+ if [[ "$file" == *"test-templates.yml" ]]; then
+ echo "Skipping test file: $file"
+ continue
+ fi
echo "Checking $file..."
if ! grep -q "workflow_call" "$file"; then
echo "Error: $file is missing workflow_call trigger"
@@ -58,69 +64,69 @@ jobs:
- test-type: "skip-pyupgrade"
skip-mypy: false
skip-pyupgrade: true
-
+
steps:
- name: Checkout code
uses: actions/checkout@v4
-
+
- name: Create test Python project
run: |
mkdir -p test-project/src/test_package
cd test-project
-
+
# Create pyproject.toml
cat > pyproject.toml << 'EOF'
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
-
+
[project]
name = "test-package"
version = "0.1.0"
description = "Test package for CI templates"
dependencies = []
-
+
[project.optional-dependencies]
dev = [
"mypy>=1.0.0",
"ruff>=0.1.0",
"pyupgrade>=3.0.0",
]
-
+
[tool.ruff]
line-length = 88
target-version = "py310"
-
+
[tool.mypy]
python_version = "3.10"
warn_return_any = true
warn_unused_configs = true
EOF
-
+
# Create source code
cat > src/test_package/__init__.py << 'EOF'
"""Test package for CI template validation."""
__version__ = "0.1.0"
-
+
def hello_world() -> str:
"""Return a greeting message."""
return "Hello, World!"
EOF
-
+
cat > src/test_package/main.py << 'EOF'
"""Main module for test package."""
from typing import List
-
+
def process_items(items: List[str]) -> List[str]:
"""Process a list of items."""
return [item.upper() for item in items]
-
+
if __name__ == "__main__":
test_items = ["hello", "world"]
result = process_items(test_items)
print(result)
EOF
-
+
- name: Test Python code quality workflow
uses: ./
with:
@@ -137,89 +143,89 @@ jobs:
matrix:
python-version: ["3.11", "3.12"]
coverage: [true, false]
-
+
steps:
- name: Checkout code
uses: actions/checkout@v4
-
+
- name: Create test Python project with tests
run: |
mkdir -p test-pytest-project/src/test_package tests
cd test-pytest-project
-
+
# Create pyproject.toml
cat > pyproject.toml << 'EOF'
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
-
+
[project]
name = "test-package"
version = "0.1.0"
description = "Test package for pytest CI template"
dependencies = []
-
+
[project.optional-dependencies]
test = [
"pytest>=7.0.0",
"pytest-cov>=4.0.0",
]
-
+
[tool.pytest.ini_options]
testpaths = ["tests"]
python_files = ["test_*.py"]
addopts = ["--strict-markers", "--strict-config"]
EOF
-
+
# Create source code
cat > src/test_package/__init__.py << 'EOF'
"""Test package for pytest template validation."""
__version__ = "0.1.0"
EOF
-
+
cat > src/test_package/calculator.py << 'EOF'
"""Simple calculator for testing."""
-
+
def add(a: float, b: float) -> float:
"""Add two numbers."""
return a + b
-
+
def multiply(a: float, b: float) -> float:
"""Multiply two numbers."""
return a * b
-
+
def divide(a: float, b: float) -> float:
"""Divide two numbers."""
if b == 0:
raise ValueError("Cannot divide by zero")
return a / b
EOF
-
+
# Create tests
cat > tests/test_calculator.py << 'EOF'
"""Tests for calculator module."""
import pytest
from test_package.calculator import add, multiply, divide
-
+
def test_add():
assert add(2, 3) == 5
assert add(-1, 1) == 0
assert add(0.1, 0.2) == pytest.approx(0.3)
-
+
def test_multiply():
assert multiply(2, 3) == 6
assert multiply(-2, 3) == -6
assert multiply(0, 5) == 0
-
+
def test_divide():
assert divide(6, 2) == 3
assert divide(5, 2) == 2.5
-
+
def test_divide_by_zero():
with pytest.raises(ValueError, match="Cannot divide by zero"):
divide(5, 0)
EOF
-
+
- name: Test pytest workflow
uses: ./
with:
@@ -237,16 +243,16 @@ jobs:
node-version: ["18", "20"]
check-yaml: [true, false]
check-json: [true, false]
-
+
steps:
- name: Checkout code
uses: actions/checkout@v4
-
+
- name: Create test web project
run: |
mkdir -p test-web-project/src/components
cd test-web-project
-
+
# Create package.json
cat > package.json << 'EOF'
{
@@ -255,19 +261,19 @@ jobs:
"description": "Test project for web formatting template"
}
EOF
-
+
# Create JavaScript files
cat > src/index.js << 'EOF'
// Test JavaScript file for formatting
const greeting = "Hello, World!";
-
+
function greet(name) {
return `Hello, ${name}!`;
}
-
+
export { greet };
EOF
-
+
cat > src/components/Button.js << 'EOF'
// Button component
export default function Button({ children, onClick }) {
@@ -278,7 +284,7 @@ jobs:
);
}
EOF
-
+
# Create JSON file
cat > config.json << 'EOF'
{
@@ -290,7 +296,7 @@ jobs:
}
}
EOF
-
+
# Create YAML file
cat > config.yml << 'EOF'
name: test-config
@@ -302,7 +308,7 @@ jobs:
- feature1
- feature2
EOF
-
+
# Create Prettier config
cat > .prettierrc.json << 'EOF'
{
@@ -313,7 +319,7 @@ jobs:
"tabWidth": 2
}
EOF
-
+
- name: Test web formatting workflow
uses: ./
with:
@@ -325,37 +331,37 @@ jobs:
test-monorepo:
runs-on: ubuntu-latest
needs: validate-syntax
-
+
steps:
- name: Checkout code
uses: actions/checkout@v4
-
+
- name: Create monorepo structure
run: |
mkdir -p monorepo-test/{backend,frontend}
-
+
# Backend Python project
cd monorepo-test/backend
cat > pyproject.toml << 'EOF'
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
-
+
[project]
name = "backend-service"
version = "0.1.0"
dependencies = []
-
+
[project.optional-dependencies]
dev = ["ruff>=0.1.0", "mypy>=1.0.0"]
EOF
-
+
mkdir -p src/backend_service
cat > src/backend_service/__init__.py << 'EOF'
"""Backend service package."""
__version__ = "0.1.0"
EOF
-
+
# Frontend project
cd ../frontend
cat > package.json << 'EOF'
@@ -364,20 +370,20 @@ jobs:
"version": "1.0.0"
}
EOF
-
+
mkdir -p src
cat > src/App.js << 'EOF'
export default function App() {
return
Hello from frontend!
;
}
EOF
-
+
- name: Test backend code quality
uses: ./
with:
working-directory: "./monorepo-test/backend"
uv-extras: "dev"
-
+
- name: Test frontend formatting
uses: ./
with:
@@ -386,11 +392,11 @@ jobs:
test-edge-cases:
runs-on: ubuntu-latest
needs: validate-syntax
-
+
steps:
- name: Checkout code
uses: actions/checkout@v4
-
+
- name: Test minimal Python project
run: |
mkdir minimal-python
@@ -399,18 +405,18 @@ jobs:
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
-
+
[project]
name = "minimal"
version = "0.1.0"
dependencies = []
EOF
-
+
mkdir -p src/minimal
cat > src/minimal/__init__.py << 'EOF'
pass
EOF
-
+
- name: Test with minimal configuration
uses: ./
with:
@@ -420,41 +426,47 @@ jobs:
test-results:
runs-on: ubuntu-latest
- needs: [test-python-code-quality, test-python-pytest, test-web-formatting, test-monorepo, test-edge-cases]
+ needs:
+ - test-python-code-quality
+ - test-python-pytest
+ - test-web-formatting
+ - test-monorepo
+ - test-edge-cases
if: always()
-
+
steps:
- name: Report test results
run: |
echo "## CI Template Test Results" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
-
- if [ "${{ needs.test-python-code-quality.result }}" == "success" ]; then
+
+ if [ "${{ needs.test-python-code-quality.result }}" == \
+ "success" ]; then
echo "✅ Python Code Quality: PASSED" >> $GITHUB_STEP_SUMMARY
else
echo "❌ Python Code Quality: FAILED" >> $GITHUB_STEP_SUMMARY
fi
-
+
if [ "${{ needs.test-python-pytest.result }}" == "success" ]; then
echo "✅ Python Pytest: PASSED" >> $GITHUB_STEP_SUMMARY
else
echo "❌ Python Pytest: FAILED" >> $GITHUB_STEP_SUMMARY
fi
-
+
if [ "${{ needs.test-web-formatting.result }}" == "success" ]; then
echo "✅ Web Formatting: PASSED" >> $GITHUB_STEP_SUMMARY
else
echo "❌ Web Formatting: FAILED" >> $GITHUB_STEP_SUMMARY
fi
-
+
if [ "${{ needs.test-monorepo.result }}" == "success" ]; then
echo "✅ Monorepo Support: PASSED" >> $GITHUB_STEP_SUMMARY
else
echo "❌ Monorepo Support: FAILED" >> $GITHUB_STEP_SUMMARY
fi
-
+
if [ "${{ needs.test-edge-cases.result }}" == "success" ]; then
echo "✅ Edge Cases: PASSED" >> $GITHUB_STEP_SUMMARY
else
echo "❌ Edge Cases: FAILED" >> $GITHUB_STEP_SUMMARY
- fi
\ No newline at end of file
+ fi
diff --git a/.gitea/workflows/web/formatting.yml b/.gitea/workflows/web/formatting.yml
index 9ae6e81..0933200 100644
--- a/.gitea/workflows/web/formatting.yml
+++ b/.gitea/workflows/web/formatting.yml
@@ -1,6 +1,7 @@
+---
name: Web/General Formatting Pipeline
-on:
+"on":
workflow_call:
inputs:
working-directory:
@@ -33,6 +34,11 @@ on:
required: false
type: boolean
default: false
+ python-version:
+ description: 'Python version to use for YAML linting (e.g., "3.12")'
+ required: false
+ type: string
+ default: "3.12"
jobs:
formatting:
@@ -40,7 +46,7 @@ jobs:
defaults:
run:
working-directory: ${{ inputs.working-directory }}
-
+
steps:
- name: Checkout code
uses: actions/checkout@v4
@@ -68,7 +74,7 @@ jobs:
if: ${{ inputs.check-yaml }}
uses: actions/setup-python@v5
with:
- python-version: "3.12"
+ python-version: ${{ inputs.python-version }}
- name: Install yamllint
if: ${{ inputs.check-yaml }}
@@ -84,4 +90,4 @@ jobs:
find . -name "*.json" -type f | while read -r file; do
echo "Checking $file"
python -m json.tool "$file" > /dev/null
- done
\ No newline at end of file
+ done
diff --git a/README.md b/README.md
index ec9260e..1e8739f 100644
--- a/README.md
+++ b/README.md
@@ -45,7 +45,7 @@ A formatting pipeline for web technologies and general file formats using Pretti
📖 [Read the full documentation](README-web-formatting.md)
-## Quick Start
+## Usage
### For Python Projects
diff --git a/scripts/validate-templates.sh b/scripts/validate-templates.sh
index fab21b7..792ef32 100755
--- a/scripts/validate-templates.sh
+++ b/scripts/validate-templates.sh
@@ -199,17 +199,26 @@ validate_workflow_file() {
log_success "$filename is a reusable workflow"
validate_workflow_inputs "$file"
else
- log_warning "$filename is not a reusable workflow (missing workflow_call trigger)"
+ # Skip warning for test files
+ if [[ "$filename" != *"test-"* ]]; then
+ log_warning "$filename is not a reusable workflow (missing workflow_call trigger)"
+ fi
fi
# Check for common issues
if grep -q "uses: \./\|uses: \.\\\\" "$file"; then
- log_warning "Found relative path in 'uses' field in $file - this may cause issues"
+ # Skip warning for test files - they intentionally use relative paths to test local workflows
+ if [[ "$filename" != *"test-"* ]]; then
+ log_warning "Found relative path in 'uses' field in $file - this may cause issues"
+ fi
fi
# Check for hardcoded values that should be inputs
if grep -q "python-version: [\"']3\." "$file"; then
- log_warning "Found hardcoded Python version in $file - consider making it an input"
+ # Skip warning for test files
+ if [[ "$filename" != *"test-"* ]]; then
+ log_warning "Found hardcoded Python version in $file - consider making it an input"
+ fi
fi
((VALID_FILES++))
diff --git a/test-validation-project/pyproject.toml b/test-validation-project/pyproject.toml
new file mode 100644
index 0000000..3e4b0f4
--- /dev/null
+++ b/test-validation-project/pyproject.toml
@@ -0,0 +1,27 @@
+[build-system]
+requires = ["hatchling"]
+build-backend = "hatchling.build"
+
+[project]
+name = "test-validation-package"
+version = "0.1.0"
+description = "Test package for CI template validation"
+dependencies = []
+
+[project.optional-dependencies]
+dev = [
+ "mypy>=1.0.0",
+ "ruff>=0.1.0",
+ "pyupgrade>=3.0.0",
+ "pytest>=7.0.0",
+ "pytest-cov>=4.0.0",
+]
+
+[tool.ruff]
+line-length = 88
+target-version = "py310"
+
+[tool.mypy]
+python_version = "3.10"
+warn_return_any = true
+warn_unused_configs = true
diff --git a/test-validation-project/src/test_package/__init__.py b/test-validation-project/src/test_package/__init__.py
new file mode 100644
index 0000000..2be14c7
--- /dev/null
+++ b/test-validation-project/src/test_package/__init__.py
@@ -0,0 +1,6 @@
+"""Test package for validation."""
+__version__ = "0.1.0"
+
+def hello_world() -> str:
+ """Return a greeting message."""
+ return "Hello, World!"
diff --git a/test-validation-project/src/test_package/math_utils.py b/test-validation-project/src/test_package/math_utils.py
new file mode 100644
index 0000000..0d1a98a
--- /dev/null
+++ b/test-validation-project/src/test_package/math_utils.py
@@ -0,0 +1,13 @@
+"""Math utility functions."""
+from typing import List
+
+def add_numbers(numbers: List[float]) -> float:
+ """Add a list of numbers."""
+ return sum(numbers)
+
+def multiply_numbers(numbers: List[float]) -> float:
+ """Multiply a list of numbers."""
+ result = 1.0
+ for num in numbers:
+ result *= num
+ return result
diff --git a/test-validation-project/tests/test_math_utils.py b/test-validation-project/tests/test_math_utils.py
new file mode 100644
index 0000000..c927c07
--- /dev/null
+++ b/test-validation-project/tests/test_math_utils.py
@@ -0,0 +1,13 @@
+"""Tests for math utilities."""
+import pytest
+from test_package.math_utils import add_numbers, multiply_numbers
+
+def test_add_numbers():
+ assert add_numbers([1, 2, 3]) == 6
+ assert add_numbers([]) == 0
+ assert add_numbers([5.5, 2.5]) == 8.0
+
+def test_multiply_numbers():
+ assert multiply_numbers([2, 3, 4]) == 24
+ assert multiply_numbers([1]) == 1
+ assert multiply_numbers([2.5, 2]) == 5.0
diff --git a/validation-report.md b/validation-report.md
new file mode 100644
index 0000000..de58dd1
--- /dev/null
+++ b/validation-report.md
@@ -0,0 +1,38 @@
+# CI Template Validation Report
+
+Generated on: $(date)
+
+## Summary
+
+This report contains the validation results for the CI template workflows.
+
+## Workflow Files
+
+### .gitea/workflows/test-templates.yml
+
+- **Size:** 13104 bytes
+- **Lines:** 472 lines
+- **Type:** Reusable workflow ✅
+- **Input parameters:** 35
+
+### .gitea/workflows/python/pytest.yml
+
+- **Size:** 3311 bytes
+- **Lines:** 111 lines
+- **Type:** Reusable workflow ✅
+- **Input parameters:** 20
+
+### .gitea/workflows/python/code-quality.yml
+
+- **Size:** 1954 bytes
+- **Lines:** 79 lines
+- **Type:** Reusable workflow ✅
+- **Input parameters:** 14
+
+### .gitea/workflows/web/formatting.yml
+
+- **Size:** 2559 bytes
+- **Lines:** 93 lines
+- **Type:** Reusable workflow ✅
+- **Input parameters:** 16
+
diff --git a/web/formatting.yml b/web/formatting.yml
deleted file mode 100644
index 9ae6e81..0000000
--- a/web/formatting.yml
+++ /dev/null
@@ -1,87 +0,0 @@
-name: Web/General Formatting Pipeline
-
-on:
- workflow_call:
- inputs:
- working-directory:
- description: 'Working directory for the project'
- required: false
- type: string
- default: "."
- node-version:
- description: 'Node.js version to use for prettier (e.g., "20")'
- required: false
- type: string
- default: "20"
- skip-prettier:
- description: 'Skip prettier formatting check'
- required: false
- type: boolean
- default: false
- prettier-config:
- description: 'Path to prettier config file (optional)'
- required: false
- type: string
- default: ""
- check-yaml:
- description: 'Check YAML files with yamllint'
- required: false
- type: boolean
- default: false
- check-json:
- description: 'Check JSON files for validity'
- required: false
- type: boolean
- default: false
-
-jobs:
- formatting:
- runs-on: ubuntu-latest
- defaults:
- run:
- working-directory: ${{ inputs.working-directory }}
-
- steps:
- - name: Checkout code
- uses: actions/checkout@v4
-
- - name: Set up Node.js
- if: ${{ !inputs.skip-prettier }}
- uses: actions/setup-node@v4
- with:
- node-version: ${{ inputs.node-version }}
-
- - name: Install prettier
- if: ${{ !inputs.skip-prettier }}
- run: npm install --save-dev --save-exact prettier
-
- - name: Run prettier check
- if: ${{ !inputs.skip-prettier }}
- run: |
- if [ -n "${{ inputs.prettier-config }}" ]; then
- npx prettier --check . --config ${{ inputs.prettier-config }}
- else
- npx prettier --check .
- fi
-
- - name: Set up Python for YAML linting
- if: ${{ inputs.check-yaml }}
- uses: actions/setup-python@v5
- with:
- python-version: "3.12"
-
- - name: Install yamllint
- if: ${{ inputs.check-yaml }}
- run: pip install yamllint
-
- - name: Check YAML files
- if: ${{ inputs.check-yaml }}
- run: yamllint .
-
- - name: Check JSON files
- if: ${{ inputs.check-json }}
- run: |
- find . -name "*.json" -type f | while read -r file; do
- echo "Checking $file"
- python -m json.tool "$file" > /dev/null
- done
\ No newline at end of file