Skip to content

Commit ac392a6

Browse files
committed
eli-420 updating report generation to get data from all environments
1 parent 46102ba commit ac392a6

File tree

3 files changed

+161
-57
lines changed

3 files changed

+161
-57
lines changed

.github/workflows/monthly-capacity-report.yml

Lines changed: 59 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,26 +26,77 @@ jobs:
2626
with:
2727
python-version: "3.11"
2828

29-
- name: "Configure AWS Credentials"
29+
# ----------------------------------------------------------------
30+
# 1. Export PROD
31+
# ----------------------------------------------------------------
32+
- name: "Configure AWS Credentials (Prod)"
3033
uses: aws-actions/configure-aws-credentials@v5
3134
with:
3235
role-to-assume: arn:aws:iam::${{ secrets.AWS_PROD_ACCOUNT_ID }}:role/service-roles/github-actions-api-deployment-role
3336
aws-region: eu-west-2
3437

35-
- name: Generate dashboard report
38+
- name: Export Dashboard (Prod)
3639
run: |
3740
chmod +x scripts/export_dashboard_image.sh
38-
./scripts/export_dashboard_image.sh Demand_And_Capacity_Prod
41+
./scripts/export_dashboard_image.sh Demand_And_Capacity_Prod Prod
3942
env:
4043
AWS_REGION: eu-west-2
4144

45+
# ----------------------------------------------------------------
46+
# 2. Export PREPROD
47+
# ----------------------------------------------------------------
48+
- name: "Configure AWS Credentials (Preprod)"
49+
uses: aws-actions/configure-aws-credentials@v5
50+
with:
51+
role-to-assume: arn:aws:iam::${{ secrets.AWS_PREPROD_ACCOUNT_ID }}:role/service-roles/github-actions-api-deployment-role
52+
aws-region: eu-west-2
53+
54+
- name: Export Dashboard (Preprod)
55+
run: ./scripts/export_dashboard_image.sh Demand_And_Capacity_Preprod Preprod
56+
env:
57+
AWS_REGION: eu-west-2
58+
59+
# ----------------------------------------------------------------
60+
# 3. Export TEST
61+
# ----------------------------------------------------------------
62+
- name: "Configure AWS Credentials (Test)"
63+
uses: aws-actions/configure-aws-credentials@v5
64+
with:
65+
role-to-assume: arn:aws:iam::${{ secrets.AWS_TEST_ACCOUNT_ID }}:role/service-roles/github-actions-api-deployment-role
66+
aws-region: eu-west-2
67+
68+
- name: Export Dashboard (Test)
69+
run: ./scripts/export_dashboard_image.sh Demand_And_Capacity_Test Test
70+
env:
71+
AWS_REGION: eu-west-2
72+
73+
# ----------------------------------------------------------------
74+
# 4. Export DEV
75+
# ----------------------------------------------------------------
76+
- name: "Configure AWS Credentials (Dev)"
77+
uses: aws-actions/configure-aws-credentials@v5
78+
with:
79+
role-to-assume: arn:aws:iam::${{ secrets.AWS_DEV_ACCOUNT_ID }}:role/service-roles/github-actions-api-deployment-role
80+
aws-region: eu-west-2
81+
82+
- name: Export Dashboard (Dev)
83+
run: ./scripts/export_dashboard_image.sh Demand_And_Capacity_Dev Dev
84+
env:
85+
AWS_REGION: eu-west-2
86+
87+
# ----------------------------------------------------------------
88+
# Generate & Notify
89+
# ----------------------------------------------------------------
90+
- name: Generate Combined Report
91+
run: python3 scripts/generate_dashboard_report.py --input dashboard_exports
92+
4293
- name: Upload report as artifact
4394
uses: actions/upload-artifact@v4
4495
with:
4596
name: capacity-report
4697
path: |
47-
dashboard_exports/*.html
48-
dashboard_exports/*.png
98+
dashboard_exports/**/*.html
99+
dashboard_exports/**/*.png
49100
retention-days: 90
50101

51102
- name: Send to Slack
@@ -54,21 +105,20 @@ jobs:
54105
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_D_AND_C_WEBHOOK }}
55106
run: |
56107
# Get the latest HTML report
57-
REPORT_FILE=$(ls -t dashboard_exports/dashboard_report_*.html | head -1)
108+
REPORT_FILE=$(find dashboard_exports -name "dashboard_report_*.html" | head -n 1)
58109
REPORT_NAME=$(basename "$REPORT_FILE")
59110
60111
# GitHub Actions URL
61112
GITHUB_URL="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
62113
63-
# Send Slack notification with simple variables for Workflow Automation
114+
# Send Slack notification
64115
curl -X POST "$SLACK_WEBHOOK_URL" \
65116
-H 'Content-Type: application/json' \
66117
-d @- <<EOF
67118
{
68-
"report_title": "📊 Monthly Demand & Capacity Report - EliD - Prod",
119+
"report_title": "📊 Monthly Demand & Capacity Report - EliD - All Envs",
69120
"report_period": "Last 8 weeks",
70121
"generated_date": "$(date +'%Y-%m-%d %H:%M UTC')",
71-
"widgets_count": "7",
72122
"github_url": "$GITHUB_URL",
73123
"report_name": "$REPORT_NAME"
74124
}

scripts/export_dashboard_image.sh

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
set -e
55

66
DASHBOARD_NAME="${1:-Demand_And_Capacity_Prod}"
7-
OUTPUT_DIR="dashboard_exports"
7+
ENVIRONMENT="${2:-Prod}"
8+
OUTPUT_BASE="dashboard_exports"
9+
OUTPUT_DIR="${OUTPUT_BASE}/${ENVIRONMENT}"
810
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
911
REGION="${AWS_REGION:-eu-west-2}"
1012

@@ -15,6 +17,7 @@ echo "========================================="
1517
echo "CloudWatch Dashboard Image Export"
1618
echo "========================================="
1719
echo "Dashboard: $DASHBOARD_NAME"
20+
echo "Environment: $ENVIRONMENT"
1821
echo "Region: $REGION"
1922
echo "Output: $OUTPUT_DIR"
2023
echo ""
@@ -49,7 +52,7 @@ import sys
4952
import os
5053
5154
# Read dashboard definition
52-
with open(f"dashboard_exports/dashboard_definition_{os.environ['TIMESTAMP']}.json") as f:
55+
with open(f"{os.environ['OUTPUT_DIR']}/dashboard_definition_{os.environ['TIMESTAMP']}.json") as f:
5356
dashboard_data = json.load(f)
5457
5558
# Parse the dashboard body
@@ -133,10 +136,4 @@ print("========================================")
133136
PYTHON_SCRIPT
134137

135138
echo ""
136-
echo "Generating HTML report..."
137-
python3 scripts/generate_dashboard_report.py --input "${OUTPUT_DIR}"
138-
139-
echo ""
140-
echo "✓ Complete! Check the ${OUTPUT_DIR}/ directory for:"
141-
echo " - Individual widget images (PNG files)"
142-
echo " - Combined HTML report (dashboard_report_*.html)"
139+
echo "✓ Export for $ENVIRONMENT complete!"

scripts/generate_dashboard_report.py

Lines changed: 96 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -36,31 +36,63 @@ def get_widget_description(title):
3636

3737
return " ".join(description_parts)
3838

39-
def generate_html_report(images_dir='dashboard_exports', output_file=None):
39+
def generate_section_html(env_name, images_dir):
4040
"""
41-
Generate an HTML report with all dashboard widget images.
42-
Images are embedded as base64 for portability.
41+
Generate HTML for a specific environment section.
4342
"""
44-
4543
images_path = Path(images_dir)
46-
4744
if not images_path.exists():
48-
print(f"Error: Directory {images_dir} not found")
49-
return None
45+
return f"<p>No data found for {env_name}</p>"
5046

51-
# Find all PNG images
5247
image_files = sorted(images_path.glob('*.png'))
53-
5448
if not image_files:
55-
print(f"Error: No PNG images found in {images_dir}")
56-
return None
49+
return f"<p>No images found for {env_name}</p>"
5750

58-
print(f"Found {len(image_files)} images to include in report")
51+
html = f"""
52+
<div class="env-section">
53+
<h2 class="env-title">{env_name}</h2>
54+
"""
55+
56+
for idx, image_file in enumerate(image_files, 1):
57+
filename = image_file.stem
58+
title = filename.split('_', 1)[1] if '_' in filename else filename
59+
title = title.replace('_', ' ')
60+
description = get_widget_description(title)
61+
62+
with open(image_file, 'rb') as f:
63+
image_data = base64.b64encode(f.read()).decode('utf-8')
64+
65+
html += f"""
66+
<div class="widget-card">
67+
<div class="widget-header">
68+
<div class="widget-title">{idx}. {title}</div>
69+
<div class="widget-description">{description}</div>
70+
</div>
71+
<div class="widget-image-container">
72+
<img class="widget-image"
73+
src="data:image/png;base64,{image_data}"
74+
alt="{title}">
75+
</div>
76+
</div>
77+
"""
78+
79+
html += "</div>"
80+
return html
81+
82+
def generate_html_report(base_dir='dashboard_exports', output_file=None):
83+
"""
84+
Generate an HTML report with all dashboard widget images from multiple environments.
85+
"""
86+
base_path = Path(base_dir)
87+
88+
if not base_path.exists():
89+
print(f"Error: Base directory {base_dir} not found")
90+
return None
5991

6092
# Default output filename
6193
if output_file is None:
6294
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
63-
output_file = f'{images_dir}/dashboard_report_{timestamp}.html'
95+
output_file = f'{base_dir}/dashboard_report_{timestamp}.html'
6496

6597
# Get dashboard name and timestamp from definition file
6698
dashboard_name = "Monthly Demand And Capacity Report - EliD"
@@ -136,6 +168,32 @@ def generate_html_report(images_dir='dashboard_exports', output_file=None):
136168
padding-bottom: 48px;
137169
}}
138170
171+
.section-header {{
172+
background: var(--nhs-white);
173+
padding: 16px 24px;
174+
margin-bottom: 24px;
175+
border-left: 8px solid var(--nhs-blue);
176+
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
177+
}}
178+
179+
.section-header h2 {{
180+
font-size: 24px;
181+
color: var(--nhs-blue);
182+
margin: 0;
183+
}}
184+
185+
.env-section {{
186+
margin-bottom: 48px;
187+
}}
188+
189+
.env-title {{
190+
font-size: 20px;
191+
color: var(--nhs-dark-grey);
192+
margin-bottom: 20px;
193+
padding-bottom: 8px;
194+
border-bottom: 2px solid #d8dde0;
195+
}}
196+
139197
.widget-card {{
140198
background: var(--nhs-white);
141199
border: 1px solid #d8dde0;
@@ -199,6 +257,11 @@ def generate_html_report(images_dir='dashboard_exports', output_file=None):
199257
border: none;
200258
border-bottom: 1px solid #ccc;
201259
}}
260+
.section-header {{
261+
border: none;
262+
padding: 0;
263+
margin-bottom: 16px;
264+
}}
202265
}}
203266
</style>
204267
</head>
@@ -216,34 +279,28 @@ def generate_html_report(images_dir='dashboard_exports', output_file=None):
216279
<div class="nhs-container content">
217280
"""
218281

219-
# Add each widget image
220-
for idx, image_file in enumerate(image_files, 1):
221-
# Extract widget title from filename (remove number prefix and extension)
222-
filename = image_file.stem
223-
# Remove leading number and underscore (e.g., "01_")
224-
title = filename.split('_', 1)[1] if '_' in filename else filename
225-
# Replace underscores with spaces
226-
title = title.replace('_', ' ')
227-
228-
description = get_widget_description(title)
229-
230-
# Read and encode image
231-
with open(image_file, 'rb') as f:
232-
image_data = base64.b64encode(f.read()).decode('utf-8')
282+
# ---------------------------------------------------------
283+
# Section 1: Production
284+
# ---------------------------------------------------------
285+
html_content += """
286+
<div class="section-header">
287+
<h2>Production Environment</h2>
288+
</div>
289+
"""
290+
html_content += generate_section_html("Prod", base_path / "Prod")
233291

234-
html_content += f"""
235-
<div class="widget-card">
236-
<div class="widget-header">
237-
<div class="widget-title">{idx}. {title}</div>
238-
<div class="widget-description">{description}</div>
239-
</div>
240-
<div class="widget-image-container">
241-
<img class="widget-image"
242-
src="data:image/png;base64,{image_data}"
243-
alt="{title}">
244-
</div>
292+
# ---------------------------------------------------------
293+
# Section 2: Preprod Environments
294+
# ---------------------------------------------------------
295+
html_content += """
296+
<div class="section-header" style="margin-top: 48px;">
297+
<h2>Preprod Environments</h2>
245298
</div>
246-
"""
299+
"""
300+
301+
# Order: Preprod, Test, Dev
302+
for env in ["Preprod", "Test", "Dev"]:
303+
html_content += generate_section_html(env, base_path / env)
247304

248305
# Close HTML
249306
html_content += """

0 commit comments

Comments
 (0)