Skip to content

feat(validation): add PR validation prompt for Next.js standards #128

feat(validation): add PR validation prompt for Next.js standards

feat(validation): add PR validation prompt for Next.js standards #128

Workflow file for this run

name: Test Action
# This workflow tests the Usable PR Validator action
# - Lints and validates scripts, templates, and documentation
# - Runs integration tests on PRs using the action itself
# - Demonstrates multi-stage validation with separate comments
on:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]
workflow_dispatch:
jobs:
lint-scripts:
name: Lint Shell Scripts
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run ShellCheck
uses: ludeeus/action-shellcheck@master
with:
scandir: './scripts'
severity: warning
validate-action:
name: Validate action.yml
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Validate Action Metadata
run: |
# Check if action.yml exists
if [ ! -f "action.yml" ]; then
echo "::error::action.yml not found"
exit 1
fi
# Validate YAML syntax
if ! command -v yq &> /dev/null; then
echo "Installing yq..."
sudo wget -qO /usr/local/bin/yq https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64
sudo chmod +x /usr/local/bin/yq
fi
yq eval '.' action.yml > /dev/null
echo "✅ action.yml is valid YAML"
# Check required fields
if ! yq eval '.name' action.yml | grep -q "Usable PR Validator"; then
echo "::error::Missing or invalid 'name' field"
exit 1
fi
echo "✅ All required fields present"
test-script-execution:
name: Test Script Execution
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Check Script Permissions
run: |
for script in scripts/*.sh; do
if [ ! -x "$script" ]; then
echo "::error::$script is not executable"
exit 1
fi
echo "✅ $script is executable"
done
- name: Test Script Syntax
run: |
for script in scripts/*.sh; do
bash -n "$script"
echo "✅ $script syntax is valid"
done
test-templates:
name: Validate Templates
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Check Templates Exist
run: |
if [ ! -d "templates" ]; then
echo "::error::templates directory not found"
exit 1
fi
if [ ! -f "templates/basic-validation.md" ]; then
echo "::error::basic-validation.md template not found"
exit 1
fi
if [ ! -f "templates/mcp-integration.md" ]; then
echo "::error::mcp-integration.md template not found"
exit 1
fi
echo "✅ All required templates present"
- name: Validate Template Content
run: |
for template in templates/*.md; do
# Check for required placeholders
if ! grep -q "{{PR_CONTEXT}}" "$template"; then
echo "::warning::$template missing {{PR_CONTEXT}} placeholder"
fi
if ! grep -q "{{BASE_BRANCH}}" "$template"; then
echo "::warning::$template missing {{BASE_BRANCH}} placeholder"
fi
echo "✅ $template validated"
done
documentation-check:
name: Check Documentation
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Check README
run: |
if [ ! -f "README.md" ]; then
echo "::error::README.md not found"
exit 1
fi
# Check for required sections
if ! grep -q "## ✨ Features" README.md; then
echo "::error::README missing Features section"
exit 1
fi
if ! grep -q "## 🚀 Quick Start" README.md; then
echo "::error::README missing Quick Start section"
exit 1
fi
echo "✅ README.md is complete"
- name: Check Other Docs
run: |
for file in LICENSE CHANGELOG.md CONTRIBUTING.md; do
if [ ! -f "$file" ]; then
echo "::error::$file not found"
exit 1
fi
echo "✅ $file exists"
done
security-check:
name: Security Checks
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Check for Secrets in Code
run: |
# Look for potential secrets or credentials (excluding comments, variable names, and GitHub Actions secret references)
if grep -rn "AKIA\|password\|secret\|token" --include="*.sh" --include="*.yml" scripts/ .github/ 2>/dev/null | \
grep -v "^[^:]*:[^:]*:#" | \
grep -v "SECRET_NAME\|MCP_SECRET\|secret-name" | \
grep -v "echo.*secret\|echo.*token" | \
grep -v "grep -rn.*secret\|grep -rn.*token" | \
grep -v "grep -v.*secret" | \
grep -v 'secrets\.' | \
grep -v "- No hardcoded\|None found" | \
grep -v "# Get the\|# Look for\|# This workflow"; then
echo "::error::Potential hardcoded secrets found in code"
exit 1
fi
echo "✅ No hardcoded secrets found"
- name: Verify Cleanup Steps
run: |
# Check that action.yml has cleanup steps
if ! grep -q "rm -f /tmp/service-account.json" action.yml; then
echo "::error::Missing cleanup for service-account.json"
exit 1
fi
if ! grep -q "rm -f /tmp/gemini-settings.json" action.yml; then
echo "::error::Missing cleanup for gemini-settings.json"
exit 1
fi
echo "✅ Cleanup steps verified"
integration-test:
name: Integration Test
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
permissions:
contents: read
pull-requests: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Determine validation base ref
id: base-ref
run: |
if [[ "${{ github.head_ref }}" == release-please--* ]]; then
# For release-please branches, validate since last release
git fetch --tags
LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
if [ -z "$LAST_TAG" ]; then
echo "base-ref=${{ github.base_ref }}" >> $GITHUB_OUTPUT
else
echo "base-ref=$LAST_TAG" >> $GITHUB_OUTPUT
fi
else
# For regular PRs, use the base branch
echo "base-ref=${{ github.base_ref }}" >> $GITHUB_OUTPUT
fi
- name: Create Test Validation Prompt
run: |
mkdir -p .github/prompts
cat > .github/prompts/test-validation.md <<'EOF'
# PR Validation Instructions
## CRITICAL OUTPUT INSTRUCTION
**START YOUR OUTPUT DIRECTLY WITH:** `# PR Validation Report`
## PR Context
{{PR_CONTEXT}}
## Your Task
Validate this PR for the usable-pr-validator GitHub Action repository.
### Step 1: Get PR Changes
```bash
# Compare base ref (branch or tag) with HEAD
# If BASE_BRANCH is a tag, use it directly; if it's a branch, try origin/ prefix
git diff {{BASE_BRANCH}}...HEAD 2>/dev/null || git diff origin/{{BASE_BRANCH}}...HEAD
```
### Step 2: Search Usable Knowledge Base
Use `agentic-search-fragments` to find relevant standards:
- Query: "GitHub Actions best practices and standards"
- Query: "Shell script security and validation standards"
- Tags: `repo:usable-pr-validator`
- Workspace: Check for coding standards and conventions
Use `get-memory-fragment-content` to read full details of relevant fragments.
### Step 3: Validation Checks
1. **Code Quality**
- Shell scripts follow best practices
- Proper error handling
- Clear variable naming
2. **Security**
- No hardcoded secrets
- Proper cleanup of sensitive data
- Secure file permissions
3. **Documentation**
- Changes are documented
- README updates if needed
- Comments are clear
4. **Action Structure**
- Inputs are properly defined
- Outputs are correctly set
- Error handling is present
## Output Format
# PR Validation Report
## Summary
[Brief overview of the changes and validation results]
## Critical Violations ❌
[Must-fix issues that would break functionality or security]
- If none, state "None found"
## Important Issues ⚠️
[Should-fix issues for code quality and best practices]
- If none, state "None found"
## Suggestions ℹ️
[Nice-to-have improvements and enhancements]
- If none, state "None found"
## Validation Outcome
- **Status**: PASS ✅ or FAIL ❌
- **Critical Issues**: [count]
- **Important Issues**: [count]
- **Suggestions**: [count]
EOF
- name: Run Action Test
id: test-action
continue-on-error: true
uses: ./
with:
prompt-file: '.github/prompts/test-validation.md'
workspace-id: '60c10ca2-4115-4c1a-b6d7-04ac39fd3938'
base-ref: ${{ steps.base-ref.outputs.base-ref }}
comment-title: 'Integration Test Validation'
comment-mode: 'update'
fail-on-critical: false
env:
GEMINI_SERVICE_ACCOUNT_KEY: ${{ secrets.GEMINI_SERVICE_ACCOUNT_KEY }}
USABLE_API_TOKEN: ${{ secrets.USABLE_API_TOKEN }}
- name: Debug Test Results
if: always()
run: |
echo "Test result: ${{ steps.test-action.outcome }}"
if [ -f "/tmp/validation-full-output.md" ]; then
echo "::group::Full Gemini Output"
cat /tmp/validation-full-output.md
echo "::endgroup::"
else
echo "⚠️ No full output file found"
fi
integration-test-documentation:
name: Integration Test (Documentation)
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
permissions:
contents: read
pull-requests: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Determine validation base ref
id: base-ref
run: |
if [[ "${{ github.head_ref }}" == release-please--* ]]; then
# For release-please branches, validate since last release
git fetch --tags
LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
if [ -z "$LAST_TAG" ]; then
echo "base-ref=${{ github.base_ref }}" >> $GITHUB_OUTPUT
else
echo "base-ref=$LAST_TAG" >> $GITHUB_OUTPUT
fi
else
# For regular PRs, use the base branch
echo "base-ref=${{ github.base_ref }}" >> $GITHUB_OUTPUT
fi
- name: Create Documentation Validation Prompt
run: |
mkdir -p .github/prompts
cat > .github/prompts/test-docs-validation.md <<'EOF'
# Documentation Validation Instructions
## CRITICAL OUTPUT INSTRUCTION
**START YOUR OUTPUT DIRECTLY WITH:** `# PR Validation Report`
## PR Context
{{PR_CONTEXT}}
## Your Task
Validate documentation changes in this PR.
### Get Changes
```bash
# Compare base ref (branch or tag) with HEAD for markdown files
# If BASE_BRANCH is a tag, use it directly; if it's a branch, try origin/ prefix
git diff {{BASE_BRANCH}}...HEAD -- '*.md' 2>/dev/null || git diff origin/{{BASE_BRANCH}}...HEAD -- '*.md'
```
### Validation Checks
1. **Completeness**
- All new features are documented
- Examples are provided
- Configuration options explained
2. **Clarity**
- Instructions are clear
- Code examples are correct
- Links are valid
3. **Consistency**
- Follows existing documentation style
- Terminology is consistent
- Formatting is proper
## Output Format
# PR Validation Report
## Summary
[Overview of documentation changes]
## Critical Violations ❌
- If none, state "None found"
## Important Issues ⚠️
- If none, state "None found"
## Suggestions ℹ️
- If none, state "None found"
## Validation Outcome
- **Status**: PASS ✅ or FAIL ❌
- **Critical Issues**: [count]
- **Important Issues**: [count]
- **Suggestions**: [count]
EOF
- name: Run Documentation Validation
id: docs-action
continue-on-error: true
uses: ./
with:
prompt-file: '.github/prompts/test-docs-validation.md'
workspace-id: '60c10ca2-4115-4c1a-b6d7-04ac39fd3938'
base-ref: ${{ steps.base-ref.outputs.base-ref }}
comment-title: 'Documentation Validation'
comment-mode: 'update'
fail-on-critical: false
env:
GEMINI_SERVICE_ACCOUNT_KEY: ${{ secrets.GEMINI_SERVICE_ACCOUNT_KEY }}
USABLE_API_TOKEN: ${{ secrets.USABLE_API_TOKEN }}
- name: Debug Documentation Results
if: always()
run: |
echo "Docs test result: ${{ steps.docs-action.outcome }}"
if [ -f "/tmp/validation-full-output.md" ]; then
echo "::group::Full Gemini Output"
cat /tmp/validation-full-output.md
echo "::endgroup::"
else
echo "⚠️ No full output file found"
fi
integration-test-comment-revalidation:
name: Integration Test (Comment Revalidation)
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
permissions:
contents: read
pull-requests: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Determine validation base ref
id: base-ref
run: |
if [[ "${{ github.head_ref }}" == release-please--* ]]; then
# For release-please branches, validate since last release
git fetch --tags
LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
if [ -z "$LAST_TAG" ]; then
echo "base-ref=${{ github.base_ref }}" >> $GITHUB_OUTPUT
else
echo "base-ref=$LAST_TAG" >> $GITHUB_OUTPUT
fi
else
# For regular PRs, use the base branch
echo "base-ref=${{ github.base_ref }}" >> $GITHUB_OUTPUT
fi
- name: Create Comment Revalidation Prompt
run: |
mkdir -p .github/prompts
cat > .github/prompts/test-comment-revalidation.md <<'EOF'
# Comment-Triggered Revalidation Test
## CRITICAL OUTPUT INSTRUCTION
**START YOUR OUTPUT DIRECTLY WITH:** `# PR Validation Report`
## PR Context
{{PR_CONTEXT}}
## Your Task
Test the comment revalidation feature.
### Step 1: Verify Override Comment
Check if there is an override/clarification comment in the PR context above (marked with 🔄).
If present:
- Acknowledge it in your report
- Parse what the user is requesting
- Test the deviation documentation feature
### Step 2: Get PR Changes
```bash
# Compare base ref (branch or tag) with HEAD
# If BASE_BRANCH is a tag, use it directly; if it's a branch, try origin/ prefix
git diff {{BASE_BRANCH}}...HEAD 2>/dev/null || git diff origin/{{BASE_BRANCH}}...HEAD
```
### Step 3: Simulate Deviation Approval
If the override comment requests approval of a deviation:
- Test creating a fragment (but mark it as a test)
- Include fragment creation in your report
## Output Format
# PR Validation Report
## Summary
[Mention this is a comment revalidation test]
[Note if override comment was detected]
## Override Comment Test Results
- **Override Detected**: Yes/No
- **Comment Author**: @[author or "none"]
- **Request Type**: [Type of request if detected]
## Critical Violations ❌
None found (test scenario)
## Important Issues ⚠️
None found (test scenario)
## Suggestions ℹ️
- Comment revalidation feature is working correctly
## Validation Outcome
- **Status**: PASS ✅
- **Test Type**: Comment Revalidation
- **Override Support**: Tested
- **Critical Issues**: 0
- **Important Issues**: 0
- **Suggestions**: 1
EOF
- name: Simulate Override Comment
id: override
run: |
# Simulate a user comment requesting deviation approval
cat <<'OVERRIDE_EOF' >> $GITHUB_OUTPUT
override-comment<<COMMENT_END
@usable This PR is a test.
Please approve this as a test of the comment revalidation feature.
This simulates a developer requesting approval for a deviation from standards.
COMMENT_END
OVERRIDE_EOF
- name: Run Comment Revalidation Test
id: comment-test
continue-on-error: true
uses: ./
with:
prompt-file: '.github/prompts/test-comment-revalidation.md'
workspace-id: '60c10ca2-4115-4c1a-b6d7-04ac39fd3938'
base-ref: ${{ steps.base-ref.outputs.base-ref }}
override-comment: ${{ steps.override.outputs.override-comment }}
comment-title: 'Comment Revalidation Test'
comment-mode: 'update'
fail-on-critical: false
env:
GEMINI_SERVICE_ACCOUNT_KEY: ${{ secrets.GEMINI_SERVICE_ACCOUNT_KEY }}
USABLE_API_TOKEN: ${{ secrets.USABLE_API_TOKEN }}
COMMENT_AUTHOR: 'test-user'
- name: Verify Override Context Was Included
if: always()
run: |
echo "Comment revalidation test result: ${{ steps.comment-test.outcome }}"
# Check if the override comment was processed
if [ -f "/tmp/validation-prompt.txt" ]; then
echo "::group::Checking Override Comment in Prompt"
if grep -q "🔄 Override/Clarification Comment" /tmp/validation-prompt.txt; then
echo "✅ Override comment marker found in prompt"
else
echo "::warning::Override comment marker NOT found in prompt"
fi
if grep -q "@usable This PR is a test" /tmp/validation-prompt.txt; then
echo "✅ Override comment content found in prompt"
else
echo "::warning::Override comment content NOT found in prompt"
fi
if grep -q "test-user" /tmp/validation-prompt.txt; then
echo "✅ Comment author found in prompt"
else
echo "::warning::Comment author NOT found in prompt"
fi
echo "::endgroup::"
else
echo "⚠️ Prompt file not found - cannot verify override context"
fi
# Check the validation output
if [ -f "/tmp/validation-full-output.md" ]; then
echo "::group::Validation Output"
cat /tmp/validation-full-output.md
echo "::endgroup::"
fi
all-checks-passed:
name: All Checks Passed
runs-on: ubuntu-latest
needs: [lint-scripts, validate-action, test-script-execution, test-templates, documentation-check, security-check]
steps:
- name: Summary
run: |
echo "🎉 All checks passed successfully!"
echo "✅ Scripts are valid and executable"
echo "✅ Action metadata is correct"
echo "✅ Templates are present"
echo "✅ Documentation is complete"
echo "✅ Security checks passed"