fix: resolve CI workflow failures (#117)
- Remove unsupported 'copilot-requests' and 'models' permissions from crawl-and-publish workflow (caused workflow file validation failure) - Add Hugo module mounts to exclude data/analyzed/*.md from Hugo's data loader (fixes 'unmarshal of format "" is not supported' build error) - Add nil-check guard to cost-dashboard shortcode for graceful degradation - Fix find_latest_summary() to resolve paths relative to root when no topic is specified (fixes test_find_latest_summary_uses_week_not_mtime) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Juan Manuel Servera committed
May 19, 2026 at 17:07 UTC
a13f8b1cf887c945506208413799ac98d5ce1d8f
4 files changed
+40
-7
.github/workflows/crawl-and-publish.yml
-3
@@ -153,8 +153,6 @@ jobs:
153
permissions:
154
actions: read
155
contents: write
156
- copilot-requests: write
157
- models: read
156
outputs:
157
week: ${{ steps.analysis-context.outputs.week }}
158
summary_file: ${{ steps.analysis-context.outputs.output_file }}
@@ -587,7 +585,6 @@ jobs:
585
runs-on: ubuntu-latest
586
permissions:
587
contents: write
590
- models: read
588
589
steps:
590
- uses: actions/checkout@v4
hugo.toml
+28
@@ -98,6 +98,34 @@ rssLimit = 20
98
url = '/index.xml'
99
weight = 80
100
101
+ignoreFiles = ['data/analyzed/.*\\.md$', 'data/metrics/']
102
+
103
+[module]
104
+ [[module.mounts]]
105
+ source = 'data/raw'
106
+ target = 'data/raw'
107
+ [[module.mounts]]
108
+ source = 'data/snapshots'
109
+ target = 'data/snapshots'
110
+ [[module.mounts]]
111
+ source = 'data/metrics'
112
+ target = 'data/metrics'
113
+ [[module.mounts]]
114
+ source = 'content'
115
+ target = 'content'
116
+ [[module.mounts]]
117
+ source = 'static'
118
+ target = 'static'
119
+ [[module.mounts]]
120
+ source = 'layouts'
121
+ target = 'layouts'
122
+ [[module.mounts]]
123
+ source = 'assets'
124
+ target = 'assets'
125
+ [[module.mounts]]
126
+ source = 'archetypes'
127
+ target = 'archetypes'
128
+
129
[markup]
130
[markup.goldmark.renderer]
131
unsafe = true
layouts/shortcodes/cost-dashboard.html
+5
-1
@@ -1,7 +1,10 @@
1
{{- $data := site.Data.metrics.cost_summary -}}
2
+{{- if not $data -}}
3
+<div class="cost-dashboard"><p>No cost data available yet.</p></div>
4
+{{- else -}}
5
{{- $weeks := $data.weeks -}}
6
{{- $cumulative := $data.cumulative_cost -}}
4
-{{- $budget := $data.budget_limit -}}
7
+{{- $budget := $data.budget_limit | default 1.0 -}}
8
{{- $pctUsed := mul (div $cumulative $budget) 100 -}}
9
10
<div class="cost-dashboard">
@@ -88,3 +91,4 @@
91
.cost-dashboard th, .cost-dashboard td { border: 1px solid #ddd; padding: 0.5rem; text-align: left; }
92
.cost-dashboard th { background: #f5f5f5; }
93
</style>
94
+{{- end -}}
scripts/generate_content.py
+7
-3
@@ -63,10 +63,14 @@ def week_from_summary_path(path: Path) -> tuple[int, int]:
63
64
def find_latest_summary(root: Path, topic_id: str | None = None) -> Path:
65
search_dir = analyzed_dir(topic_id)
66
- candidates = list(search_dir.glob(f"*{SUMMARY_SUFFIX}"))
67
- if not candidates:
68
- # Fallback: try legacy path via root
66
+ # When using default (relative) path, resolve via root for backward compat
67
+ if topic_id is None:
68
candidates = list(root.glob(f"data/analyzed/*{SUMMARY_SUFFIX}"))
69
+ else:
70
+ candidates = list(search_dir.glob(f"*{SUMMARY_SUFFIX}"))
71
+ if not candidates:
72
+ # Fallback: try the other approach
73
+ candidates = list(search_dir.glob(f"*{SUMMARY_SUFFIX}")) if topic_id is None else list(root.glob(f"data/analyzed/*{SUMMARY_SUFFIX}"))
74
if not candidates:
75
raise GenerationError("No analyzed summaries found under data/analyzed/.")
76
return max(candidates, key=week_from_summary_path)