Skip to content

Commit b8c0d9e

Browse files
committed
initial commit
1 parent d245991 commit b8c0d9e

File tree

7 files changed

+497
-0
lines changed

7 files changed

+497
-0
lines changed
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
name: Update Workshop Page
2+
3+
on:
4+
schedule:
5+
- cron: '0 6 * * *' # Every day at 06:00 UTC
6+
workflow_dispatch: # Optional: allows manual runs from the Actions tab
7+
8+
jobs:
9+
update-html:
10+
runs-on: ubuntu-latest
11+
12+
steps:
13+
- name: Checkout main branch
14+
uses: actions/checkout@v4
15+
with:
16+
persist-credentials: false # We'll use a deploy token
17+
18+
- name: Set up Node.js
19+
uses: actions/setup-node@v4
20+
with:
21+
node-version: '20'
22+
23+
- name: Install dependencies
24+
run: npm install
25+
26+
- name: Generate all_test.html
27+
env:
28+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
29+
run: npm run generate
30+
31+
- name: Commit and push if changed
32+
env:
33+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
34+
run: |
35+
git config user.name "GitHub Actions"
36+
git config user.email "[email protected]"
37+
git remote set-url origin https://x-access-token:${GITHUB_TOKEN}@github.com/${{ github.repository }}
38+
git add all_test.html featured_workshops.html
39+
git diff --cached --quiet || git commit -m "Update workshop lists [auto]"
40+
git push origin HEAD:master
41+

images/rc-logo-square.png

87.7 KB
Loading

manual_all_list.html

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<!-- This html is added below the automatically generated content on the "all.html" list of Research Commons workshops -->
2+
3+
<section>
4+
<h2>Research Data Management (RDM)</h2>
5+
<ul>
6+
<li><a href="https://ubc-library-rc.github.io/rdm/content/01_file_naming.html"> File Naming</a></li>
7+
<li> <a href="https://ubc-library-rc.github.io/rdm/content/02_file_formats.html"> File Formats</a></li>
8+
<li> <a href="https://ubc-library-rc.github.io/rdm/content/03_create_readme.html"> Creating a README file</a></li>
9+
<li><a href="https://ubc-library-rc.github.io/rdm/content/07_data_dictionary.html"> Creating a Data Dictionary</a> </li>
10+
<li><a href="https://ubc-library-rc.github.io/rdm/content/04_directory_structures.html"> Directories Structure</a> </li>
11+
<li><a href="https://ubc-library-rc.github.io/Introduction-to-Markdown/"> Introduction to Markdown for Research Data Management</a></li>
12+
<li><a href="https://ubc-library-rc.github.io/Introduction-to-Markdown/content/02_create_readme_with_md.html"> Create a README with Markdown</a></li>
13+
<li><a href="https://ubc-library-rc.github.io/Introduction-to-Markdown/content/03_extended_md.html"> Advanced Markdown</a></li>
14+
<li><a href="https://ubc-library-rc.github.io/intro-metadata/"> Metadata basics: describing research data</a></li>
15+
<li><a href="https://ubc-library-rc.github.io/rdm/content/05-1_Basic_Deposit.html"> Deposit in UBC Dataverse Collection: Basic Deposit</a></li>
16+
<li><a href="https://ubc-library-rc.github.io/rdm/content/05-2_Advanced_Deposit.html"> Deposit in UBC Dataverse Collection: Advanced Deposit</a></li>
17+
<li><a href="https://ubc-library-rc.github.io/rdm/content/05-3_Admin_Access.html"> Deposit in UBC Dataverse Collection: Admin Deposit</a></li>
18+
<li><a href="https://ubc-library-rc.github.io/rdm/content/05-4_Geospatial_Deposit.html"> Deposit in UBC Dataverse Collection: Geomatics Deposit</a></li>
19+
<li><a href="https://osf.io/ht9qn/"> Introduction to the OSF</a></li>
20+
<li><a href="https://ubc-library-rc.github.io/rdm/content/06_Data_Management_Plan.html"> Create a Data Management Plan</a></li>
21+
<li><a href="https://ubc-library-rc.github.io/rdm/content/08_Simplified-Data-Management-Plan.html"> Create a Simplified Data Management Plan</a></li>
22+
</ul>
23+
</section>
24+
<section>
25+
<h2>Citation management</h2>
26+
<ul>
27+
<li><a href="https://researchcommons.library.ubc.ca/beginner">Choose the right Citation Management Tool for your Research (Beginner)</a></li>
28+
<li><a href="https://researchcommons.library.ubc.ca/citation-management-using-zotero-intermediate">Citation Management using Zotero (Intermediate)</a></li>
29+
<li><a href="https://researchcommons.library.ubc.ca/citation-management-using-mendeley-intermediate">Citation Management using Mendeley (Intermediate)</a></li>
30+
</ul>
31+
</section>
32+

manual_featured_list.html

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<!-- This html is added below the automatically generated content on the "index.html" list of Research Commons workshops -->
2+
3+
<section>
4+
<h2>Research Data Management (RDM)</h2>
5+
<div class="workshop-grid">
6+
<div class="workshop-card">
7+
<a href="https://ubc-library-rc.github.io/rdm/content/01_file_naming.html" target="_blank" rel="noopener noreferrer">File naming</a>
8+
<p class="blurb">Learn how to name your data files</p>
9+
</div>
10+
<div class="workshop-card">
11+
<a href="https://ubc-library-rc.github.io/rdm/content/02_file_formats.html" target="_blank" rel="noopener noreferrer">File formatting</a>
12+
<p class="blurb">Learn what data formats to use</p>
13+
</div>
14+
<div class="workshop-card">
15+
<a href="https://ubc-library-rc.github.io/rdm/content/03_create_readme.html" target="_blank" rel="noopener noreferrer">Create a README file</a>
16+
<p class="blurb">Learn how to create good README files</p>
17+
</div>
18+
<div class="workshop-card">
19+
<a href="https://ubc-library-rc.github.io/rdm/content/07_data_dictionary.html" target="_blank" rel="noopener noreferrer">Create a data dictionary</a>
20+
<p class="blurb">Learn how to create a good data dictionary or a code book</p>
21+
</div>
22+
<div class="workshop-card">
23+
<a href="https://ubc-library-rc.github.io/rdm/content/04_directory_structures.html" target="_blank" rel="noopener noreferrer">Directories structure</a>
24+
<p class="blurb">Learn to organize your data directories </p>
25+
</div>
26+
<div class="workshop-card">
27+
<a href="https://ubc-library-rc.github.io/Introduction-to-Markdown/" target="_blank" rel="noopener noreferrer">Introduction to Markdown for research data</a>
28+
<p class="blurb">Learn how to use Markdown with research data</p>
29+
</div>
30+
<div class="workshop-card">
31+
<a href="https://ubc-library-rc.github.io/rdm/content/05-1_Basic_Deposit.html" target="_blank" rel="noopener noreferrer">Deposit in UBC Dataverse Collection: Basic deposit</a>
32+
<p class="blurb">Learn how to deposit your data in Borealis repository</p>
33+
</div>
34+
<div class="workshop-card">
35+
<a href="https://ubc-library-rc.github.io/rdm/content/06_Data_Management_Plan.html" target="_blank" rel="noopener noreferrer">Create a Data Management Plan (DMP)</a>
36+
<p class="blurb">Learn how to create a variety of Data Management Plans</p>
37+
</div>
38+
<div class="workshop-card">
39+
<a href="https://ubc-library-rc.github.io/rdm/content/08_Simplified-Data-Management-Plan.html" target="_blank" rel="noopener noreferrer">Create a Simplified Data Management Plan </a>
40+
<p class="blurb">Learn how to create a Simplified Data Management Plan for the Tri-Agency grant applications</p>
41+
</div>
42+
</div>
43+
</section>

package.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"name": "ubc-rc-html-builder",
3+
"type": "module",
4+
"scripts": {
5+
"generate": "node scripts/generate.js"
6+
}
7+
}

scripts/generate.js

Lines changed: 267 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,267 @@
1+
#!/usr/bin/env node
2+
3+
import fs from "node:fs";
4+
5+
const ORG = "ubc-library-rc"; // replace if needed
6+
const TOKEN = process.env.GITHUB_TOKEN;
7+
8+
const TOPIC_LABELS = {
9+
data: "Data analysis and visualization",
10+
"digital-scholarship": "Digital scholarship",
11+
geospatial: "Geographic information systems (GIS) and mapping",
12+
// "research-data-management": "Research data management", --exclude RDM, which is added manually
13+
};
14+
15+
// -----------------------------
16+
// Helpers
17+
// -----------------------------
18+
19+
async function fetchAllRepos(headers) {
20+
let allRepos = [];
21+
let page = 1;
22+
let fetched;
23+
do {
24+
const res = await fetch(
25+
`https://api.github.com/orgs/${ORG}/repos?per_page=100&page=${page}`,
26+
{ headers }
27+
);
28+
if (!res.ok) throw new Error(`HTTP ${res.status}: repos page ${page}`);
29+
fetched = await res.json();
30+
allRepos = allRepos.concat(fetched);
31+
page++;
32+
} while (fetched.length === 100);
33+
return allRepos;
34+
}
35+
36+
async function fetchRepoTopics(repo, headers) {
37+
const res = await fetch(`https://api.github.com/repos/${ORG}/${repo}/topics`, {
38+
headers: { ...headers, Accept: "application/vnd.github+json" },
39+
});
40+
if (!res.ok) return { names: [] };
41+
return res.json();
42+
}
43+
44+
async function fetchRepoReadme(repo, headers) {
45+
const res = await fetch(`https://api.github.com/repos/${ORG}/${repo}/readme`, {
46+
headers,
47+
});
48+
if (!res.ok) return "";
49+
const data = await res.json();
50+
if (!data.content) return "";
51+
return Buffer.from(data.content, "base64").toString("utf-8");
52+
}
53+
54+
function extractTitleAndBlurb(readme) {
55+
let title = null;
56+
let blurb = null;
57+
if (!readme) return { title, blurb };
58+
59+
const lines = readme.split(/\r?\n/);
60+
for (const line of lines) {
61+
if (!title && line.startsWith("#")) {
62+
title = line.replace(/^#+\s*/, "").trim();
63+
}
64+
if (!blurb && line.startsWith("Description:")) {
65+
blurb = line.replace("Description:", "").trim();
66+
}
67+
if (title && blurb) break;
68+
}
69+
return { title, blurb };
70+
}
71+
72+
// -----------------------------
73+
// Main
74+
// -----------------------------
75+
76+
async function main() {
77+
const headers = {
78+
"User-Agent": "gh-actions",
79+
Accept: "application/vnd.github+json",
80+
...(TOKEN ? { Authorization: `token ${TOKEN}` } : {}),
81+
};
82+
83+
const repos = await fetchAllRepos(headers);
84+
85+
const enriched = [];
86+
const featured = [];
87+
88+
for (const repo of repos) {
89+
if (!repo.description) continue;
90+
91+
try {
92+
const topics = await fetchRepoTopics(repo.name, headers);
93+
const readme = await fetchRepoReadme(repo.name, headers);
94+
const { title, blurb } = extractTitleAndBlurb(readme);
95+
96+
const finalTitle = title || repo.description || repo.name;
97+
98+
const enrichedRepo = {
99+
name: repo.name,
100+
title: finalTitle,
101+
blurb,
102+
url: `https://${ORG}.github.io/${repo.name}/`,
103+
archived: repo.archived,
104+
topics: topics.names || [],
105+
};
106+
107+
if (topics.names && topics.names.includes("workshop")) {
108+
enriched.push(enrichedRepo);
109+
}
110+
if (topics.names && topics.names.includes("featured")) {
111+
featured.push(enrichedRepo);
112+
}
113+
} catch (e) {
114+
console.warn(`⚠️ Skipping ${repo.name}: ${e.message}`);
115+
}
116+
}
117+
118+
// -----------------------------
119+
// Group by predefined topics
120+
// -----------------------------
121+
function groupRepos(repos) {
122+
const grouped = {};
123+
for (const topic of Object.keys(TOPIC_LABELS)) {
124+
grouped[topic] = repos
125+
.filter((r) => r.topics.includes(topic))
126+
.sort((a, b) => a.title.localeCompare(b.title));
127+
}
128+
return grouped;
129+
}
130+
131+
const groupedAll = groupRepos(enriched);
132+
const groupedFeatured = groupRepos(featured);
133+
134+
// -----------------------------
135+
// Manually listed workshops
136+
// -----------------------------
137+
let nonRepoWorkshops = "";
138+
try {
139+
nonRepoWorkshops = fs.readFileSync("manual_all_list.html", "utf8");
140+
} catch (err) {
141+
console.warn("⚠️ Could not load manual_all_list.html:", err.message);
142+
}
143+
144+
// -----------------------------
145+
// Manually listed featured workshops
146+
// -----------------------------
147+
let nonRepoFeaturedWorkshops = "";
148+
try {
149+
nonRepoFeaturedWorkshops = fs.readFileSync("manual_featured_list.html", "utf8");
150+
} catch (err) {
151+
console.warn("⚠️ Could not load manual_featured_list.html:", err.message);
152+
}
153+
154+
// -----------------------------
155+
// Generate all.html
156+
// -----------------------------
157+
const sectionsAll = Object.entries(groupedAll)
158+
.map(([topic, repos]) => {
159+
if (!repos.length) return "";
160+
const items = repos
161+
.map((repo) => {
162+
const text = repo.title + (repo.archived ? " (archived)" : "");
163+
const cls = repo.archived ? 'class="archived"' : "";
164+
return `<li><a ${cls} href="${repo.url}" target="_blank" rel="noopener noreferrer">${text}</a></li>`;
165+
})
166+
.join("\n");
167+
return `<section>
168+
<h2>${TOPIC_LABELS[topic]}</h2>
169+
<ul>${items}</ul>
170+
</section>`;
171+
})
172+
.join("\n\n");
173+
174+
const htmlAll = `<!DOCTYPE html>
175+
<html lang="en">
176+
<head>
177+
<meta charset="UTF-8">
178+
<title>UBC Library Research Commons - Open Educational Materials</title>
179+
<link rel="stylesheet" href="style.css">
180+
</head>
181+
<body>
182+
<section>
183+
<div class="header-flex">
184+
<div id="header-img">
185+
<img src="images/rc-logo-square.png" alt="UBC Research Commons logo"/>
186+
</div>
187+
<div id="header-text">
188+
UBC Library Research Commons
189+
</div>
190+
<div id="header-link">
191+
<a href="https://github.com/${ORG}/">github.com/${ORG}</a>
192+
</div>
193+
</div>
194+
</section>
195+
<h1>Past and present workshops offered by the Research Commons</h1>
196+
<p>For currently scheduled workshops visit <a href="https://researchcommons.library.ubc.ca/events/">https://researchcommons.library.ubc.ca/events/</a></p>
197+
${sectionsAll}
198+
${nonRepoWorkshops}
199+
</body>
200+
</html>`;
201+
202+
fs.writeFileSync("all.html", htmlAll);
203+
204+
// -----------------------------
205+
// Generate index.html
206+
// -----------------------------
207+
const sectionsFeatured = Object.entries(groupedFeatured)
208+
.map(([topic, repos]) => {
209+
if (!repos.length) return "";
210+
const items = repos
211+
.map((repo) => {
212+
const text = repo.title + (repo.archived ? " (archived)" : "");
213+
const cls = repo.archived ? 'class="archived"' : "";
214+
const blurbText = repo.blurb
215+
? `<p class="blurb">${repo.blurb}</p>`
216+
: "";
217+
return `<div class="workshop-card">
218+
<a ${cls} href="${repo.url}" target="_blank" rel="noopener noreferrer">${text}</a>
219+
${blurbText}
220+
</div>`;
221+
})
222+
.join("\n");
223+
return `<section>
224+
<h2>${TOPIC_LABELS[topic]}</h2>
225+
<div class="workshop-grid">
226+
${items}
227+
</div>
228+
</section>`;
229+
})
230+
.join("\n\n");
231+
232+
const htmlFeatured = `<!DOCTYPE html>
233+
<html lang="en">
234+
<head>
235+
<meta charset="UTF-8">
236+
<title>UBC Library Research Commons - Featured workshops</title>
237+
<link rel="stylesheet" href="style.css">
238+
</head>
239+
<body>
240+
<section>
241+
<div class="header-flex">
242+
<div id="header-img">
243+
<img src="images/rc-logo-square.png" alt="UBC Research Commons logo"/>
244+
</div>
245+
<div id="header-text">
246+
UBC Library Research Commons
247+
</div>
248+
<div id="header-link">
249+
<a href="https://github.com/${ORG}/">github.com/${ORG}</a>
250+
</div>
251+
</div>
252+
</section>
253+
<h1>Featured Workshops</h1>
254+
${sectionsFeatured}
255+
${nonRepoFeaturedWorkshops}
256+
</body>
257+
</html>`;
258+
259+
fs.writeFileSync("index.html", htmlFeatured);
260+
261+
console.log("✅ Pages generated: all.html, index.html");
262+
}
263+
264+
main().catch((err) => {
265+
console.error(err);
266+
process.exit(1);
267+
});

0 commit comments

Comments
 (0)