Skip to content

v6.3.0: Unify document paths to storage/ directory #21

v6.3.0: Unify document paths to storage/ directory

v6.3.0: Unify document paths to storage/ directory #21

name: MUSUBI Reusable Workflow

Check failure on line 1 in .github/workflows/musubi-reusable.yml

View workflow run for this annotation

GitHub Actions / .github/workflows/musubi-reusable.yml

Invalid workflow file

(Line: 42, Col: 1): 'permissions' is already defined
permissions:
contents: read
issues: write
pull-requests: write
on:
workflow_call:
inputs:
command:
description: 'MUSUBI command to run'
type: string
default: 'validate'
feature:
description: 'Feature name to analyze'
type: string
required: false
fail-on-gaps:
description: 'Fail if gaps found'
type: boolean
default: false
constitution-check:
description: 'Run constitutional check'
type: boolean
default: true
post-comment:
description: 'Post comment on PR'
type: boolean
default: true
outputs:
validation-result:
description: 'Validation result'
value: ${{ jobs.musubi.outputs.validation-result }}
coverage:
description: 'Coverage percentage'
value: ${{ jobs.musubi.outputs.coverage }}
gaps-count:
description: 'Number of gaps'
value: ${{ jobs.musubi.outputs.gaps-count }}
permissions:
contents: read
pull-requests: write
jobs:
musubi:
name: MUSUBI Validation
runs-on: ubuntu-latest
outputs:
validation-result: ${{ steps.validate.outputs.result }}
coverage: ${{ steps.analyze.outputs.coverage }}
gaps-count: ${{ steps.gaps.outputs.count }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
cache: 'npm'
- name: Install Dependencies
run: npm ci || npm install
- name: Install MUSUBI
run: npm install -g musubi-sdd
- name: Constitutional Check
id: constitution
if: inputs.constitution-check
run: |
echo "πŸ›οΈ Constitutional Governance Check"
if [ -f "steering/rules/constitution.md" ]; then
npx musubi validate --constitution && echo "result=passed" >> $GITHUB_OUTPUT || echo "result=failed" >> $GITHUB_OUTPUT
else
echo "⚠️ No constitution.md found"
echo "result=skipped" >> $GITHUB_OUTPUT
fi
- name: Validate
id: validate
if: contains(fromJson('["validate", "all"]'), inputs.command)
run: |
echo "βœ… Running Validation"
if npx musubi validate ${{ inputs.feature && format('--feature {0}', inputs.feature) || '' }}; then
echo "result=passed" >> $GITHUB_OUTPUT
else
echo "result=failed" >> $GITHUB_OUTPUT
exit 1
fi
- name: Analyze
id: analyze
if: contains(fromJson('["analyze", "all"]'), inputs.command)
run: |
echo "πŸ“Š Running Analysis"
RESULT=$(npx musubi analyze --format json ${{ inputs.feature && format('--feature {0}', inputs.feature) || '' }} 2>/dev/null || echo '{"coverage":0}')
COVERAGE=$(echo "$RESULT" | jq -r '.coverage // 0')
echo "coverage=$COVERAGE" >> $GITHUB_OUTPUT
echo "Coverage: $COVERAGE%"
- name: Check Gaps
id: gaps
if: contains(fromJson('["gaps", "trace", "all"]'), inputs.command)
run: |
echo "πŸ”— Checking Traceability Gaps"
RESULT=$(npx musubi gaps --format json ${{ inputs.feature && format('--feature {0}', inputs.feature) || '' }} 2>/dev/null || echo '{"gaps":[]}')
COUNT=$(echo "$RESULT" | jq '.gaps | length // 0')
echo "count=$COUNT" >> $GITHUB_OUTPUT
echo "Gaps: $COUNT"
if [ "$COUNT" -gt 0 ] && [ "${{ inputs.fail-on-gaps }}" = "true" ]; then
echo "❌ Gaps found, failing"
npx musubi gaps ${{ inputs.feature && format('--feature {0}', inputs.feature) || '' }}
exit 1
fi
- name: Generate Report
id: report
run: |
cat << 'EOF' > musubi-report.md
## πŸŽ‹ MUSUBI SDD Report
| Check | Status |
|-------|--------|
| Constitutional | ${{ steps.constitution.outputs.result || 'N/A' }} |
| Validation | ${{ steps.validate.outputs.result || 'N/A' }} |
| Coverage | ${{ steps.analyze.outputs.coverage || 'N/A' }}% |
| Gaps | ${{ steps.gaps.outputs.count || 'N/A' }} |
---
*Generated by [MUSUBI SDD](https://github.com/nahisaho/MUSUBI)*
EOF
echo "path=musubi-report.md" >> $GITHUB_OUTPUT
- name: Comment on PR
if: github.event_name == 'pull_request' && inputs.post-comment
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const report = fs.readFileSync('musubi-report.md', 'utf8');
// Find existing comment
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
});
const botComment = comments.find(c =>
c.user.type === 'Bot' && c.body.includes('MUSUBI SDD Report')
);
if (botComment) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: botComment.id,
body: report
});
} else {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: report
});
}