Skip to content

Commit 88a0b96

Browse files
committed
Switch from Jekyll posts to GitHub Discussions for weekly updates
- Update CI workflow to create Discussion posts instead of committing files - Add JavaScript RSS feed reader to dynamically fetch and display discussions - Remove old Jekyll posts and archive page - Weekly updates now posted to 'Weekly Updates' discussion category
1 parent ad9e191 commit 88a0b96

5 files changed

Lines changed: 210 additions & 101 deletions

File tree

.github/workflows/fvutils-weekly-report.yaml

Lines changed: 33 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -6,23 +6,14 @@ on:
66
workflow_dispatch:
77

88
permissions:
9-
contents: write
9+
contents: read
1010
pull-requests: read
11+
discussions: write
1112

1213
jobs:
1314
generate-news:
1415
runs-on: ubuntu-latest
1516
steps:
16-
- name: Checkout
17-
uses: actions/checkout@v4
18-
with:
19-
fetch-depth: 0
20-
21-
- name: Configure Git
22-
run: |
23-
git config user.name "github-actions[bot]"
24-
git config user.email "github-actions[bot]@users.noreply.github.com"
25-
2617
- name: Install GitHub CLI
2718
run: |
2819
type -p gh >/dev/null || (curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg \
@@ -98,53 +89,48 @@ EOFPROMPT
9889

9990
gh copilot suggest -p "$(cat /tmp/detail_prompt.txt)" --model gpt-5-mini > /tmp/detailed_overview.txt
10091

101-
- name: Create News Post
92+
- name: Create Discussion Post
93+
env:
94+
GH_TOKEN: ${{ github.token }}
10295
run: |
103-
POST_DATE=$(date -u +%Y-%m-%d)
10496
WEEK_NUM=$(date -u +%V)
10597
YEAR=$(date -u +%Y)
106-
POST_FILE="_posts/${POST_DATE}-weekly-update-${YEAR}-w${WEEK_NUM}.md"
98+
TITLE="Weekly Update - Week $WEEK_NUM, $YEAR"
10799
108-
cat > "$POST_FILE" << 'EOFPOST'
109-
---
110-
layout: post
111-
title: "FVUtils Weekly Update - Week WEEK_NUM, YEAR"
112-
date: POST_DATE
113-
---
114-
115-
SHORT_NEWS
100+
# Combine short summary and detailed overview
101+
BODY=$(cat << 'EOFBODY'
102+
$(cat /tmp/short_news.txt)
116103

117104
## Detailed Activity Overview
118105

119-
DETAILED_OVERVIEW
106+
$(cat /tmp/detailed_overview.txt)
120107

121108
---
122109

123110
*This weekly update was automatically generated based on activity across FVUtils repositories.*
124-
EOFPOST
125-
126-
sed -i "s/WEEK_NUM/$WEEK_NUM/g" "$POST_FILE"
127-
sed -i "s/YEAR/$YEAR/g" "$POST_FILE"
128-
sed -i "s/POST_DATE/$POST_DATE/g" "$POST_FILE"
111+
EOFBODY
112+
)
129113

130-
sed -i "/SHORT_NEWS/r /tmp/short_news.txt" "$POST_FILE"
131-
sed -i "/SHORT_NEWS/d" "$POST_FILE"
114+
# Evaluate the variables in the body
115+
BODY=$(eval echo "$BODY")
132116

133-
sed -i "/DETAILED_OVERVIEW/r /tmp/detailed_overview.txt" "$POST_FILE"
134-
sed -i "/DETAILED_OVERVIEW/d" "$POST_FILE"
117+
# Escape the body for JSON
118+
BODY_JSON=$(jq -n --arg body "$BODY" '$body')
135119

136-
echo "Created post: $POST_FILE"
137-
cat "$POST_FILE"
138-
139-
- name: Commit and Push
140-
run: |
141-
git add _posts/*.md
142-
if git diff --staged --quiet; then
143-
echo "No changes to commit"
144-
else
145-
POST_DATE=$(date -u +%Y-%m-%d)
146-
WEEK_NUM=$(date -u +%V)
147-
git commit -m "Add weekly update for week $WEEK_NUM"
148-
git push
149-
echo "Weekly news post published!"
150-
fi
120+
# Create the discussion using GraphQL API
121+
gh api graphql -f query="
122+
mutation {
123+
createDiscussion(input: {
124+
repositoryId: \"R_kgDOHMTiUw\"
125+
categoryId: \"DIC_kwDOHMTiU84C2BrA\"
126+
title: \"$TITLE\"
127+
body: $BODY_JSON
128+
}) {
129+
discussion {
130+
id
131+
url
132+
title
133+
}
134+
}
135+
}
136+
" | jq -r '.data.createDiscussion.discussion | "Created discussion: \(.title)\nURL: \(.url)"'

_posts/2026-02-07-welcome.md

Lines changed: 0 additions & 24 deletions
This file was deleted.

archive.html

Lines changed: 0 additions & 14 deletions
This file was deleted.

index.md

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -208,21 +208,12 @@ title: Home
208208
</div>
209209
</div>
210210

211-
<div class="news-section">
212-
<h2>Latest News</h2>
213-
{% if site.posts.size > 0 %}
214-
<ul class="news-list">
215-
{% for post in site.posts limit:5 %}
216-
<li class="news-item">
217-
<div class="news-date">{{ post.date | date_to_string }}</div>
218-
<h3 class="news-title"><a href="{{ post.url | absolute_url }}">{{ post.title }}</a></h3>
219-
<p class="news-excerpt">{{ post.excerpt | strip_html | truncatewords: 30 }}</p>
220-
</li>
221-
{% endfor %}
222-
</ul>
223-
<p><a href="/archive.html">View all news →</a></p>
224-
{% else %}
225-
<p>Check back soon for updates on FVUtils projects!</p>
226-
{% endif %}
211+
<div id="weekly-updates-container">
212+
<div class="news-section">
213+
<h2>Weekly Updates</h2>
214+
<p>Loading weekly updates...</p>
215+
</div>
227216
</div>
228217

218+
<script src="{{ '/public/js/discussion-feed.js' | relative_url }}"></script>
219+

public/js/discussion-feed.js

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
/**
2+
* Fetch and display GitHub Discussions RSS feed for Weekly Updates
3+
*/
4+
(function() {
5+
'use strict';
6+
7+
const RSS_FEED_URL = 'https://github.com/fvutils/fvutils.github.io/discussions.rss';
8+
const CATEGORY_SLUG = 'weekly-updates';
9+
const MAX_ITEMS = 5;
10+
11+
/**
12+
* Fetch and parse the RSS feed
13+
*/
14+
async function fetchDiscussions() {
15+
try {
16+
const response = await fetch(RSS_FEED_URL);
17+
if (!response.ok) {
18+
throw new Error(`HTTP error! status: ${response.status}`);
19+
}
20+
21+
const text = await response.text();
22+
const parser = new DOMParser();
23+
const xmlDoc = parser.parseFromString(text, 'text/xml');
24+
25+
// Check for parsing errors
26+
const parserError = xmlDoc.querySelector('parsererror');
27+
if (parserError) {
28+
throw new Error('XML parsing error');
29+
}
30+
31+
return parseRSSItems(xmlDoc);
32+
} catch (error) {
33+
console.error('Error fetching discussions:', error);
34+
return null;
35+
}
36+
}
37+
38+
/**
39+
* Parse RSS items and filter for Weekly Updates category
40+
*/
41+
function parseRSSItems(xmlDoc) {
42+
const items = xmlDoc.querySelectorAll('item');
43+
const discussions = [];
44+
45+
items.forEach(item => {
46+
const link = item.querySelector('link')?.textContent || '';
47+
const title = item.querySelector('title')?.textContent || '';
48+
const pubDate = item.querySelector('pubDate')?.textContent || '';
49+
const description = item.querySelector('description')?.textContent || '';
50+
51+
// Filter by category slug in the link
52+
// Discussion links look like: https://github.com/fvutils/fvutils.github.io/discussions/categories/weekly-updates/...
53+
if (link.includes(`/categories/${CATEGORY_SLUG}`)) {
54+
discussions.push({
55+
title: title,
56+
link: link,
57+
date: new Date(pubDate),
58+
description: description
59+
});
60+
}
61+
});
62+
63+
// Sort by date (newest first) and limit to MAX_ITEMS
64+
discussions.sort((a, b) => b.date - a.date);
65+
return discussions.slice(0, MAX_ITEMS);
66+
}
67+
68+
/**
69+
* Format date as readable string
70+
*/
71+
function formatDate(date) {
72+
const options = { year: 'numeric', month: 'long', day: 'numeric' };
73+
return date.toLocaleDateString('en-US', options);
74+
}
75+
76+
/**
77+
* Extract plain text excerpt from HTML description
78+
*/
79+
function getExcerpt(html, maxWords = 30) {
80+
const tempDiv = document.createElement('div');
81+
tempDiv.innerHTML = html;
82+
const text = tempDiv.textContent || tempDiv.innerText || '';
83+
const words = text.trim().split(/\s+/);
84+
85+
if (words.length > maxWords) {
86+
return words.slice(0, maxWords).join(' ') + '...';
87+
}
88+
return text;
89+
}
90+
91+
/**
92+
* Render discussions in the container
93+
*/
94+
function renderDiscussions(discussions) {
95+
const container = document.getElementById('weekly-updates-container');
96+
if (!container) {
97+
console.error('Container #weekly-updates-container not found');
98+
return;
99+
}
100+
101+
if (!discussions || discussions.length === 0) {
102+
container.innerHTML = `
103+
<div class="news-section">
104+
<h2>Weekly Updates</h2>
105+
<p>Check back soon for updates on FVUtils projects!</p>
106+
</div>
107+
`;
108+
return;
109+
}
110+
111+
let html = `
112+
<div class="news-section">
113+
<h2>Weekly Updates</h2>
114+
<ul class="news-list">
115+
`;
116+
117+
discussions.forEach(discussion => {
118+
html += `
119+
<li class="news-item">
120+
<div class="news-date">${formatDate(discussion.date)}</div>
121+
<h3 class="news-title"><a href="${discussion.link}">${discussion.title}</a></h3>
122+
<p class="news-excerpt">${getExcerpt(discussion.description)}</p>
123+
</li>
124+
`;
125+
});
126+
127+
html += `
128+
</ul>
129+
<p><a href="https://github.com/fvutils/fvutils.github.io/discussions/categories/weekly-updates">View all updates →</a></p>
130+
</div>
131+
`;
132+
133+
container.innerHTML = html;
134+
}
135+
136+
/**
137+
* Show error message
138+
*/
139+
function showError() {
140+
const container = document.getElementById('weekly-updates-container');
141+
if (container) {
142+
container.innerHTML = `
143+
<div class="news-section">
144+
<h2>Weekly Updates</h2>
145+
<p>Check back soon for updates on FVUtils projects!</p>
146+
</div>
147+
`;
148+
}
149+
}
150+
151+
/**
152+
* Initialize - fetch and render discussions
153+
*/
154+
async function init() {
155+
const discussions = await fetchDiscussions();
156+
157+
if (discussions === null) {
158+
showError();
159+
} else {
160+
renderDiscussions(discussions);
161+
}
162+
}
163+
164+
// Run when DOM is ready
165+
if (document.readyState === 'loading') {
166+
document.addEventListener('DOMContentLoaded', init);
167+
} else {
168+
init();
169+
}
170+
})();

0 commit comments

Comments
 (0)