Skip to content

Commit 837c7c0

Browse files
committed
SpecMem GitHub action and dashboard deploy
1 parent 47f8ed5 commit 837c7c0

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

70 files changed

+11578
-1120
lines changed
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
# SpecMem Dashboard Deploy Action
2+
3+
Deploy a static SpecMem dashboard to GitHub Pages for free hosting.
4+
5+
## ⚠️ Important Limitations
6+
7+
- **Static Dashboard**: This deploys a read-only snapshot of your spec data. No live search or real-time updates.
8+
- **GitHub Pages Conflict**: If your repository already uses GitHub Pages for documentation (MkDocs, Jekyll, Docusaurus, etc.), this action will deploy to a subdirectory to avoid conflicts.
9+
- **Data Freshness**: Dashboard data is only as fresh as the last CI run.
10+
11+
## Quick Start
12+
13+
```yaml
14+
name: Deploy Dashboard
15+
on:
16+
push:
17+
branches: [main]
18+
19+
jobs:
20+
deploy:
21+
runs-on: ubuntu-latest
22+
permissions:
23+
contents: write
24+
steps:
25+
- uses: actions/checkout@v4
26+
- uses: specmem/specmem/.github/actions/specmem-dashboard@main
27+
with:
28+
github_token: ${{ secrets.GITHUB_TOKEN }}
29+
```
30+
31+
## Inputs
32+
33+
| Input | Description | Default |
34+
|-------|-------------|---------|
35+
| `deploy_path` | Path within GitHub Pages | `specmem-dashboard` |
36+
| `force` | Force deployment even if conflicts detected | `false` |
37+
| `include_history` | Include historical trend data | `true` |
38+
| `history_limit` | Maximum history entries to keep | `30` |
39+
| `install_from` | Installation source: `pypi` or `github` | `pypi` |
40+
| `version` | SpecMem version or git ref | `latest` |
41+
| `github_repo` | GitHub repo for installation | `specmem/specmem` |
42+
| `github_token` | GitHub token for deployment | **required** |
43+
| `python_version` | Python version to use | `3.11` |
44+
| `working_directory` | Directory to run analysis in | `.` |
45+
46+
## Outputs
47+
48+
| Output | Description |
49+
|--------|-------------|
50+
| `dashboard_url` | URL of deployed dashboard |
51+
| `export_path` | Path to exported data |
52+
53+
## Examples
54+
55+
### Basic Usage
56+
57+
```yaml
58+
- uses: specmem/specmem/.github/actions/specmem-dashboard@main
59+
with:
60+
github_token: ${{ secrets.GITHUB_TOKEN }}
61+
```
62+
63+
### Custom Deploy Path
64+
65+
```yaml
66+
- uses: specmem/specmem/.github/actions/specmem-dashboard@main
67+
with:
68+
github_token: ${{ secrets.GITHUB_TOKEN }}
69+
deploy_path: specs # Deploy to /specs/ instead of /specmem-dashboard/
70+
```
71+
72+
### With Historical Trends
73+
74+
```yaml
75+
- uses: specmem/specmem/.github/actions/specmem-dashboard@main
76+
with:
77+
github_token: ${{ secrets.GITHUB_TOKEN }}
78+
include_history: true
79+
history_limit: 50 # Keep last 50 data points
80+
```
81+
82+
### Monorepo Support
83+
84+
```yaml
85+
- uses: specmem/specmem/.github/actions/specmem-dashboard@main
86+
with:
87+
github_token: ${{ secrets.GITHUB_TOKEN }}
88+
working_directory: packages/my-app
89+
deploy_path: my-app-specs
90+
```
91+
92+
## GitHub Pages Conflicts
93+
94+
If your repository already uses GitHub Pages for documentation, the action will:
95+
96+
1. **Detect conflicts** - Check for `mkdocs.yml`, `_config.yml`, `docusaurus.config.js`, etc.
97+
2. **Warn you** - Display a warning about potential conflicts
98+
3. **Deploy to subdirectory** - By default, deploys to `/specmem-dashboard/` to avoid overwriting your docs
99+
100+
### Workarounds
101+
102+
**Option 1: Use a subdirectory (recommended)**
103+
```yaml
104+
deploy_path: specmem-dashboard # Your docs stay at root, dashboard at /specmem-dashboard/
105+
```
106+
107+
**Option 2: Force deployment (use with caution)**
108+
```yaml
109+
force: true # May overwrite existing content
110+
```
111+
112+
**Option 3: Use a different branch**
113+
Configure GitHub Pages to serve from a different branch for your docs.
114+
115+
## Dashboard Features
116+
117+
The static dashboard includes:
118+
119+
- 📊 **Overview** - Coverage %, health grade, validation errors
120+
- 📋 **Specs Browser** - Browse all specifications with client-side search
121+
- 📈 **Trends** - Historical coverage and health charts (if history enabled)
122+
- 📜 **Guidelines** - View coding guidelines from all formats
123+
124+
## License
125+
126+
MIT
Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
name: 'SpecMem Dashboard Deploy'
2+
description: 'Deploy static SpecMem dashboard to GitHub Pages'
3+
author: 'SpecMem'
4+
5+
branding:
6+
icon: 'bar-chart-2'
7+
color: 'purple'
8+
9+
inputs:
10+
deploy_path:
11+
description: 'Path within GitHub Pages (default: specmem-dashboard)'
12+
required: false
13+
default: 'specmem-dashboard'
14+
force:
15+
description: 'Force deployment even if conflicts detected'
16+
required: false
17+
default: 'false'
18+
include_history:
19+
description: 'Include historical trend data'
20+
required: false
21+
default: 'true'
22+
history_limit:
23+
description: 'Maximum number of history entries to keep'
24+
required: false
25+
default: '30'
26+
install_from:
27+
description: 'Installation source: pypi or github'
28+
required: false
29+
default: 'pypi'
30+
version:
31+
description: 'SpecMem version (PyPI) or ref (GitHub)'
32+
required: false
33+
default: 'latest'
34+
github_repo:
35+
description: 'GitHub repo for installation (owner/repo)'
36+
required: false
37+
default: 'specmem/specmem'
38+
github_token:
39+
description: 'GitHub token for deployment'
40+
required: true
41+
python_version:
42+
description: 'Python version to use'
43+
required: false
44+
default: '3.11'
45+
working_directory:
46+
description: 'Directory to run analysis in'
47+
required: false
48+
default: '.'
49+
50+
outputs:
51+
dashboard_url:
52+
description: 'URL of deployed dashboard'
53+
value: ${{ steps.deploy.outputs.dashboard_url }}
54+
export_path:
55+
description: 'Path to exported data'
56+
value: ${{ steps.export.outputs.export_path }}
57+
58+
runs:
59+
using: 'composite'
60+
steps:
61+
- name: Set up Python
62+
uses: actions/setup-python@v5
63+
with:
64+
python-version: ${{ inputs.python_version }}
65+
66+
- name: Cache pip packages
67+
uses: actions/cache@v4
68+
with:
69+
path: ~/.cache/pip
70+
key: specmem-dashboard-${{ inputs.install_from }}-${{ inputs.version }}-${{ runner.os }}
71+
restore-keys: |
72+
specmem-dashboard-${{ inputs.install_from }}-
73+
specmem-dashboard-
74+
75+
- name: Install SpecMem
76+
shell: bash
77+
run: |
78+
echo "::group::Installing SpecMem"
79+
if [ "${{ inputs.install_from }}" = "github" ]; then
80+
if [ "${{ inputs.version }}" = "latest" ] || [ "${{ inputs.version }}" = "main" ]; then
81+
pip install "git+https://github.com/${{ inputs.github_repo }}.git"
82+
else
83+
pip install "git+https://github.com/${{ inputs.github_repo }}.git@${{ inputs.version }}"
84+
fi
85+
else
86+
if [ "${{ inputs.version }}" = "latest" ]; then
87+
pip install specmem
88+
else
89+
pip install "specmem==${{ inputs.version }}"
90+
fi
91+
fi
92+
echo "::endgroup::"
93+
specmem --version || echo "SpecMem installed"
94+
95+
- name: Export spec data
96+
id: export
97+
shell: bash
98+
working-directory: ${{ inputs.working_directory }}
99+
run: |
100+
echo "::group::Exporting spec data"
101+
102+
HISTORY_FLAG=""
103+
if [ "${{ inputs.include_history }}" = "true" ]; then
104+
HISTORY_FLAG="--include-history"
105+
else
106+
HISTORY_FLAG="--no-history"
107+
fi
108+
109+
specmem export data \
110+
--output .specmem/export \
111+
$HISTORY_FLAG \
112+
--history-limit ${{ inputs.history_limit }}
113+
114+
echo "export_path=.specmem/export" >> $GITHUB_OUTPUT
115+
echo "::endgroup::"
116+
117+
- name: Build static dashboard
118+
shell: bash
119+
working-directory: ${{ inputs.working_directory }}
120+
run: |
121+
echo "::group::Building static dashboard"
122+
specmem export build \
123+
--data .specmem/export \
124+
--output .specmem/static \
125+
--base-path "/${{ inputs.deploy_path }}/"
126+
echo "::endgroup::"
127+
128+
- name: Check for conflicts
129+
shell: bash
130+
working-directory: ${{ inputs.working_directory }}
131+
run: |
132+
echo "::group::Checking for conflicts"
133+
python3 << 'EOF'
134+
import os
135+
import sys
136+
from pathlib import Path
137+
138+
# Check for existing GitHub Pages content
139+
conflict_patterns = [
140+
"index.html", "_config.yml", "mkdocs.yml",
141+
"docusaurus.config.js", "docusaurus.config.ts",
142+
"book.toml", "conf.py", "_sidebar.md"
143+
]
144+
145+
deploy_path = "${{ inputs.deploy_path }}"
146+
force = "${{ inputs.force }}" == "true"
147+
148+
# For root deployment, check repo root
149+
if deploy_path in [".", "", "/"]:
150+
check_dir = Path(".")
151+
else:
152+
check_dir = Path(".")
153+
154+
conflicts = []
155+
for pattern in conflict_patterns:
156+
if (check_dir / pattern).exists():
157+
conflicts.append(pattern)
158+
159+
if conflicts and not force:
160+
print("::warning::Existing GitHub Pages content detected:")
161+
for c in conflicts:
162+
print(f" - {c}")
163+
print("")
164+
print("The dashboard will be deployed to /${{ inputs.deploy_path }}/ to avoid conflicts.")
165+
print("Use force: true to override this behavior.")
166+
elif conflicts and force:
167+
print("::warning::Force mode enabled - existing content may be affected")
168+
169+
print("Conflict check complete")
170+
EOF
171+
echo "::endgroup::"
172+
173+
- name: Deploy to GitHub Pages
174+
id: deploy
175+
uses: peaceiris/actions-gh-pages@v4
176+
with:
177+
github_token: ${{ inputs.github_token }}
178+
publish_dir: ${{ inputs.working_directory }}/.specmem/static
179+
destination_dir: ${{ inputs.deploy_path }}
180+
keep_files: true
181+
182+
- name: Output dashboard URL
183+
shell: bash
184+
run: |
185+
REPO_NAME="${{ github.repository }}"
186+
OWNER="${REPO_NAME%%/*}"
187+
REPO="${REPO_NAME##*/}"
188+
189+
# Construct GitHub Pages URL
190+
DASHBOARD_URL="https://${OWNER}.github.io/${REPO}/${{ inputs.deploy_path }}/"
191+
192+
echo "dashboard_url=${DASHBOARD_URL}" >> $GITHUB_OUTPUT
193+
echo ""
194+
echo "📊 Dashboard deployed!"
195+
echo " URL: ${DASHBOARD_URL}"
196+
echo ""
197+
echo "⚠️ Note: This is a STATIC dashboard."
198+
echo " Data is from the last CI run, not live."

0 commit comments

Comments
 (0)