|
| 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