tofUI Dashboard Publishing
July 16, 2026 ยท View on GitHub
Integrated dashboard publishing system for tracking tofUI reports across multiple repositories.
Overview
tofUI now includes built-in support for publishing report metadata to a centralized dashboard. This allows you to track all your Terraform reports across multiple repositories and folders in one place.
Features
- ๐ Centralized Tracking: Track all reports across multiple repositories
- ๐ Folder Organization: Reports organized by repository and folder
- ๐ฏ Report Types: Separate tracking for test (PR) and build (merge) reports
- ๐ Slot-Based Storage: 7 slots per report type per folder (14 total)
- ๐จ Visual Status Badges: Color-coded status indicators
- ๐ Static Dashboard: No server required - pure JavaScript
Quick Start
1. Set Up Dashboard Repository
Create a repository for your dashboard (e.g., myorg/tofui-dashboard) and copy the dashboard files from this repo's static-dashboard/ directory to it. Enable GitHub Pages on the gh-pages branch.
2. Generate Report with Dashboard Publishing
# Test report (for pull requests) - default when --apply-mode is NOT used
tofui plan.json \
--build-name "pr-456" \
--github-repo "myorg/infrastructure" \
--folder "aws_us_east_2" \
--dashboard-repo "myorg/tofui-dashboard" \
--status terraform_plan:2
# Build report (for merges/deploys) - when --apply-mode is used
# apply-mode reads the apply log; it requires --stdout-tf-log and --terraform-exit-code
tofui \
--apply-mode \
--stdout-tf-log apply.log \
--terraform-exit-code 0 \
--build-name "deploy-123" \
--github-repo "myorg/infrastructure" \
--folder "aws_us_east_2" \
--dashboard-repo "myorg/tofui-dashboard" \
--status terraform_apply:0
Parameters
Required for Dashboard Publishing
--dashboard-repo: Dashboard repository (owner/repo) - automatically enables dashboard publishing--github-repo: Source repository (owner/repo) - used for both GitHub Pages upload and dashboard tracking
Optional
--apply-mode: When present, marks report as "build" type (for merges/deploys). Without it, defaults to "test" type (for PRs)--status: Status indicators in formattype:code(can be specified multiple times)--folder: Folder name for organizing reports--github-enterprise-url: GitHub Enterprise URL
Automatic Features
- HTML URL: Automatically captured from GitHub Pages upload - no need to specify manually
- Dashboard Publishing: Automatically enabled when
--dashboard-repois present - Report Type: Automatically determined by
--apply-modeflag (build if present, test otherwise)
Report Types
Test Reports (Pull Requests)
# Default behavior - no --apply-mode flag
tofui plan.json \
--build-name "pr-456" \
--github-repo "myorg/infrastructure" \
--dashboard-repo "myorg/tofui-dashboard" \
--status terraform_plan:2
Build Reports (Merges/Deploys)
# Use --apply-mode to mark as build report
tofui \
--apply-mode \
--stdout-tf-log apply.log \
--terraform-exit-code 0 \
--build-name "deploy-123" \
--github-repo "myorg/infrastructure" \
--dashboard-repo "myorg/tofui-dashboard" \
--status terraform_apply:0
Status Indicators
Status indicators track the outcome of various checks. Format: --status type:code
Common Status Types
terraform_plan
0: No Changes1: Error2: Has Changes
terraform_apply
0: Success1: Failed
tfsec
0: Passed1: Failed2: Warnings
tflint
0: Passed1: Failed
codebuild
0: Success1: Failed2: In Progress
Custom Status Types
You can use any status type name. Define the display formatting in the dashboard's config.json:
{
"status_types": {
"my_custom_check": {
"name": "My Custom Check",
"mappings": {
"0": {"label": "Passed", "emoji": "โ
", "color": "#1a7f37"},
"1": {"label": "Failed", "emoji": "โ", "color": "#cf222e"}
}
}
}
}
Complete Example
#!/bin/bash
# Complete CI/CD workflow with dashboard publishing
# For Pull Requests (test reports)
if [ "$CI_EVENT_TYPE" = "pull_request" ]; then
# Run terraform plan
terraform plan -out=plan.tfplan -detailed-exitcode
PLAN_EXIT=$?
# Convert to JSON
terraform show -json plan.tfplan > plan.json
# Run security checks
tfsec . --format json > tfsec.json
TFSEC_EXIT=$?
# Generate test report (no --apply-mode)
tofui plan.json \
--build-name "pr-${PR_NUMBER}" \
--display-name "PR #${PR_NUMBER} Validation" \
--github-repo "myorg/infrastructure" \
--folder "production" \
--dashboard-repo "myorg/tofui-dashboard" \
--status "terraform_plan:${PLAN_EXIT}" \
--status "tfsec:${TFSEC_EXIT}"
# For Merges/Deploys (build reports)
else
# Run terraform apply, capturing the log
terraform apply -auto-approve 2>&1 | tee apply.log
APPLY_EXIT=${PIPESTATUS[0]}
# Generate build report (with --apply-mode)
tofui \
--apply-mode \
--stdout-tf-log apply.log \
--terraform-exit-code "${APPLY_EXIT}" \
--build-name "deploy-${BUILD_ID}" \
--display-name "Production Deploy #${BUILD_ID}" \
--github-repo "myorg/infrastructure" \
--folder "production" \
--dashboard-repo "myorg/tofui-dashboard" \
--status "terraform_apply:${APPLY_EXIT}"
fi
Dashboard Configuration
Configure repositories and folders in the dashboard's config.json:
{
"status_types": {
"terraform_plan": {
"name": "Terraform Plan",
"mappings": {
"0": {"label": "No Changes", "emoji": "โ
", "color": "#1a7f37"},
"1": {"label": "Error", "emoji": "โ", "color": "#cf222e"},
"2": {"label": "Has Changes", "emoji": "๐", "color": "#0969da"}
}
}
},
"repositories": {
"myorg/infrastructure": {
"display_name": "๐๏ธ Infrastructure",
"folders": ["aws_us_east_1", "aws_us_east_2", "production"]
},
"myorg/networking": {
"display_name": "๐ Networking"
}
}
}
How It Works
Slot-Based Storage
Each repo/folder/type combination has 7 slots:
- Publisher finds the oldest slot and overwrites it
- Dashboard fetches all 7 slots for each configured repo/folder/type
- No index file needed - predictable filenames
File Naming
Reports are stored as: {repo}-{folder}-{type}-{slot}.json
Example:
myorg-infrastructure-production-test-001.json
myorg-infrastructure-production-test-002.json
...
myorg-infrastructure-production-build-001.json
myorg-infrastructure-production-build-002.json
Concurrent Safety
- Each repo/folder/type runs sequentially
- Exponential backoff retry (12 attempts)
- No race conditions between different report types
GitHub Enterprise
# Test report
tofui plan.json \
--build-name "pr-123" \
--github-repo "myorg/infrastructure" \
--github-enterprise-url "https://github.company.com" \
--dashboard-repo "myorg/tofui-dashboard" \
--status terraform_plan:2
# Build report
tofui \
--apply-mode \
--stdout-tf-log apply.log \
--terraform-exit-code 0 \
--build-name "deploy-123" \
--github-repo "myorg/infrastructure" \
--github-enterprise-url "https://github.company.com" \
--dashboard-repo "myorg/tofui-dashboard" \
--status terraform_apply:0
Troubleshooting
Dashboard Not Showing Reports
- Check that
config.jsonincludes your repository - Verify GitHub Pages is enabled on
gh-pagesbranch - Check browser console for errors
- Ensure reports were published successfully
Publishing Fails
- Verify
GITHUB_TOKENenvironment variable is set - Check token has
reposcope - Ensure dashboard repository exists
- Verify
gh-pagesbranch exists
Migration from tofUI+
If you were using the standalone tofui-publish command:
Before (tofUI+ standalone):
tofui plan.json --build-name "deploy-123"
tofui-publish --dashboard-repo "myorg/dashboard" --source-repo "myorg/infra" --report-type build ...
After (integrated):
# Test report (default)
tofui plan.json \
--build-name "pr-123" \
--github-repo "myorg/infra" \
--dashboard-repo "myorg/dashboard" \
--status terraform_plan:2
# Build report (with --apply-mode)
tofui \
--apply-mode \
--stdout-tf-log apply.log \
--terraform-exit-code 0 \
--build-name "deploy-123" \
--github-repo "myorg/infra" \
--dashboard-repo "myorg/dashboard" \
--status terraform_apply:0
Changes:
- โ
--publish-dashboardflag removed - automatically enabled when--dashboard-repois present - โ
--report-typeparameter removed - automatically determined by--apply-modeflag - โ
--html-urlparameter removed - automatically captured from GitHub Pages upload
Dashboard URL
After publishing, your dashboard will be available at:
- Public GitHub:
https://myorg.github.io/tofui-dashboard - GitHub Enterprise:
https://pages.github.company.com/myorg/tofui-dashboard
Made with โค๏ธ by Bob