@rmdes/indiekit-endpoint-github 1.0.4 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/styles.css +18 -39
- package/index.js +2 -0
- package/lib/controllers/changelog.js +166 -0
- package/lib/controllers/dashboard.js +7 -44
- package/lib/github-client.js +7 -2
- package/package.json +1 -1
- package/views/activity.njk +2 -2
- package/views/commits.njk +2 -2
- package/views/contributions.njk +2 -2
- package/views/github.njk +14 -20
- package/views/layouts/github.njk +6 -0
- package/views/stars.njk +2 -2
package/assets/styles.css
CHANGED
|
@@ -1,14 +1,6 @@
|
|
|
1
1
|
/* GitHub endpoint styles */
|
|
2
2
|
|
|
3
|
-
/*
|
|
4
|
-
.github-section {
|
|
5
|
-
margin-block-end: var(--space-xl);
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
.github-section h2 {
|
|
9
|
-
margin-block-end: var(--space-m);
|
|
10
|
-
}
|
|
11
|
-
|
|
3
|
+
/* Profile */
|
|
12
4
|
.github-profile {
|
|
13
5
|
align-items: center;
|
|
14
6
|
display: flex;
|
|
@@ -36,7 +28,7 @@
|
|
|
36
28
|
font-size: var(--step--1);
|
|
37
29
|
}
|
|
38
30
|
|
|
39
|
-
/*
|
|
31
|
+
/* List */
|
|
40
32
|
.github-list {
|
|
41
33
|
display: flex;
|
|
42
34
|
flex-direction: column;
|
|
@@ -63,7 +55,7 @@
|
|
|
63
55
|
gap: var(--space-xs);
|
|
64
56
|
}
|
|
65
57
|
|
|
66
|
-
/* Activity
|
|
58
|
+
/* Activity */
|
|
67
59
|
.github-activity {
|
|
68
60
|
align-items: center;
|
|
69
61
|
}
|
|
@@ -83,20 +75,20 @@
|
|
|
83
75
|
color: var(--color-text-secondary);
|
|
84
76
|
}
|
|
85
77
|
|
|
86
|
-
/* Commit
|
|
78
|
+
/* Commit message (in main list) */
|
|
87
79
|
.github-commit__message {
|
|
88
80
|
flex: 1;
|
|
89
81
|
min-inline-size: 200px;
|
|
90
82
|
}
|
|
91
83
|
|
|
92
|
-
/* Commit list
|
|
84
|
+
/* Commit list (inside featured repos) */
|
|
93
85
|
.github-commit-list {
|
|
94
86
|
display: flex;
|
|
95
87
|
flex-direction: column;
|
|
96
88
|
font-size: var(--step--1);
|
|
97
89
|
gap: var(--space-xs);
|
|
98
90
|
list-style: none;
|
|
99
|
-
margin:
|
|
91
|
+
margin: 0;
|
|
100
92
|
padding: 0;
|
|
101
93
|
}
|
|
102
94
|
|
|
@@ -116,24 +108,11 @@
|
|
|
116
108
|
color: var(--color-text-secondary);
|
|
117
109
|
}
|
|
118
110
|
|
|
119
|
-
/* Featured repos
|
|
111
|
+
/* Featured repos */
|
|
120
112
|
.github-featured {
|
|
121
113
|
display: grid;
|
|
122
114
|
gap: var(--space-l);
|
|
123
115
|
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
|
|
124
|
-
margin-block-end: var(--space-xl);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
.github-featured__commits {
|
|
128
|
-
border-block-start: 1px solid var(--color-border);
|
|
129
|
-
margin-block-start: var(--space-s);
|
|
130
|
-
padding-block-start: var(--space-s);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
.github-featured__commits summary {
|
|
134
|
-
color: var(--color-text-secondary);
|
|
135
|
-
cursor: pointer;
|
|
136
|
-
font-size: var(--step--1);
|
|
137
116
|
}
|
|
138
117
|
|
|
139
118
|
.github-featured__desc {
|
|
@@ -161,6 +140,13 @@
|
|
|
161
140
|
padding: var(--space-m);
|
|
162
141
|
}
|
|
163
142
|
|
|
143
|
+
/* Details inside featured cards: add separator */
|
|
144
|
+
.github-featured__repo .details {
|
|
145
|
+
border-block-start: 1px solid var(--color-border);
|
|
146
|
+
margin-block-start: var(--space-s);
|
|
147
|
+
padding-block-start: var(--space-s);
|
|
148
|
+
}
|
|
149
|
+
|
|
164
150
|
/* Language indicator */
|
|
165
151
|
.github-lang {
|
|
166
152
|
margin-inline-end: var(--space-xs);
|
|
@@ -172,7 +158,7 @@
|
|
|
172
158
|
font-size: var(--step--1);
|
|
173
159
|
}
|
|
174
160
|
|
|
175
|
-
/* Repo card
|
|
161
|
+
/* Repo card */
|
|
176
162
|
.github-repo {
|
|
177
163
|
flex-direction: column;
|
|
178
164
|
}
|
|
@@ -192,7 +178,7 @@
|
|
|
192
178
|
font-weight: var(--font-weight-semibold);
|
|
193
179
|
}
|
|
194
180
|
|
|
195
|
-
/* SHA badge
|
|
181
|
+
/* SHA badge */
|
|
196
182
|
.github-sha {
|
|
197
183
|
background: var(--color-offset);
|
|
198
184
|
border-radius: var(--radius-s);
|
|
@@ -201,7 +187,7 @@
|
|
|
201
187
|
padding-inline: var(--space-2xs);
|
|
202
188
|
}
|
|
203
189
|
|
|
204
|
-
/* Star
|
|
190
|
+
/* Star card */
|
|
205
191
|
.github-star {
|
|
206
192
|
flex-direction: column;
|
|
207
193
|
}
|
|
@@ -220,12 +206,7 @@
|
|
|
220
206
|
font-weight: var(--font-weight-semibold);
|
|
221
207
|
}
|
|
222
208
|
|
|
223
|
-
/*
|
|
224
|
-
* Link styles - grouped by specificity (ascending)
|
|
225
|
-
* Non-pseudo selectors first, then pseudo selectors
|
|
226
|
-
*/
|
|
227
|
-
|
|
228
|
-
/* Specificity: 0,1,1 (one class, one element) */
|
|
209
|
+
/* Link styles */
|
|
229
210
|
.github-featured__name a {
|
|
230
211
|
text-decoration: none;
|
|
231
212
|
}
|
|
@@ -234,12 +215,10 @@
|
|
|
234
215
|
text-decoration: none;
|
|
235
216
|
}
|
|
236
217
|
|
|
237
|
-
/* Specificity: 0,1,2 (one class, two elements) */
|
|
238
218
|
.github-commit-list code a {
|
|
239
219
|
text-decoration: none;
|
|
240
220
|
}
|
|
241
221
|
|
|
242
|
-
/* Pseudo-class selectors */
|
|
243
222
|
.github-featured__name a:hover {
|
|
244
223
|
text-decoration: underline;
|
|
245
224
|
}
|
package/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import express from "express";
|
|
2
2
|
|
|
3
3
|
import { activityController } from "./lib/controllers/activity.js";
|
|
4
|
+
import { changelogController } from "./lib/controllers/changelog.js";
|
|
4
5
|
import { commitsController } from "./lib/controllers/commits.js";
|
|
5
6
|
import { contributionsController } from "./lib/controllers/contributions.js";
|
|
6
7
|
import { dashboardController } from "./lib/controllers/dashboard.js";
|
|
@@ -85,6 +86,7 @@ export default class GitHubEndpoint {
|
|
|
85
86
|
publicRouter.get("/api/contributions", contributionsController.api);
|
|
86
87
|
publicRouter.get("/api/activity", activityController.api);
|
|
87
88
|
publicRouter.get("/api/featured", featuredController.api);
|
|
89
|
+
publicRouter.get("/api/changelog", changelogController.api);
|
|
88
90
|
|
|
89
91
|
return publicRouter;
|
|
90
92
|
}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { GitHubClient } from "../github-client.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Categorize a repo by its name prefix
|
|
5
|
+
* @param {string} name - Repository name
|
|
6
|
+
* @returns {string} - Category key
|
|
7
|
+
*/
|
|
8
|
+
function categorizeRepo(name) {
|
|
9
|
+
if (name === "indiekit") return "core";
|
|
10
|
+
if (name === "indiekit-cloudron" || name === "indiekit-deploy")
|
|
11
|
+
return "deployment";
|
|
12
|
+
if (name.includes("theme")) return "theme";
|
|
13
|
+
if (name.startsWith("indiekit-endpoint-")) return "endpoints";
|
|
14
|
+
if (name.startsWith("indiekit-syndicator-")) return "syndicators";
|
|
15
|
+
if (name.startsWith("indiekit-post-type-")) return "post-types";
|
|
16
|
+
if (name.startsWith("indiekit-preset-")) return "presets";
|
|
17
|
+
return "other";
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const CATEGORY_LABELS = {
|
|
21
|
+
core: "Core",
|
|
22
|
+
deployment: "Deployment",
|
|
23
|
+
theme: "Theme",
|
|
24
|
+
endpoints: "Endpoints",
|
|
25
|
+
syndicators: "Syndicators",
|
|
26
|
+
"post-types": "Post Types",
|
|
27
|
+
presets: "Presets",
|
|
28
|
+
other: "Other",
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Split an array into chunks of a given size
|
|
33
|
+
* @param {Array} array
|
|
34
|
+
* @param {number} size
|
|
35
|
+
* @returns {Array<Array>}
|
|
36
|
+
*/
|
|
37
|
+
function chunks(array, size) {
|
|
38
|
+
const result = [];
|
|
39
|
+
for (let i = 0; i < array.length; i += size) {
|
|
40
|
+
result.push(array.slice(i, i + size));
|
|
41
|
+
}
|
|
42
|
+
return result;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Changelog API controller
|
|
47
|
+
* @type {import("express").RequestHandler}
|
|
48
|
+
*/
|
|
49
|
+
export const changelogController = {
|
|
50
|
+
async api(request, response, next) {
|
|
51
|
+
try {
|
|
52
|
+
const { username, token, cacheTtl } =
|
|
53
|
+
request.app.locals.application.githubConfig;
|
|
54
|
+
|
|
55
|
+
if (!username) {
|
|
56
|
+
return response.status(400).json({ error: "No username configured" });
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const client = new GitHubClient({ token, cacheTtl });
|
|
60
|
+
|
|
61
|
+
// Parse days param — default 30, "all" for unlimited
|
|
62
|
+
const daysParam = request.query.days || "30";
|
|
63
|
+
let sinceDate = null;
|
|
64
|
+
let daysValue = daysParam;
|
|
65
|
+
|
|
66
|
+
if (daysParam !== "all") {
|
|
67
|
+
const days = Number.parseInt(daysParam, 10);
|
|
68
|
+
if (Number.isNaN(days) || days < 1) {
|
|
69
|
+
return response
|
|
70
|
+
.status(400)
|
|
71
|
+
.json({ error: "Invalid days parameter" });
|
|
72
|
+
}
|
|
73
|
+
daysValue = days;
|
|
74
|
+
const since = new Date();
|
|
75
|
+
since.setDate(since.getDate() - days);
|
|
76
|
+
sinceDate = since.toISOString();
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Fetch all user repos (100 to cover all indiekit repos)
|
|
80
|
+
const repos = await client.getUserRepos(username, 100, "pushed");
|
|
81
|
+
|
|
82
|
+
if (!Array.isArray(repos)) {
|
|
83
|
+
return response.json({
|
|
84
|
+
commits: [],
|
|
85
|
+
categories: {},
|
|
86
|
+
totalCommits: 0,
|
|
87
|
+
days: daysValue,
|
|
88
|
+
generatedAt: new Date().toISOString(),
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Filter to indiekit repos only
|
|
93
|
+
const indiekitRepos = repos.filter((repo) =>
|
|
94
|
+
repo.name.includes("indiekit"),
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
// Build categories map from discovered repos
|
|
98
|
+
const categories = {};
|
|
99
|
+
for (const repo of indiekitRepos) {
|
|
100
|
+
const cat = categorizeRepo(repo.name);
|
|
101
|
+
if (!categories[cat]) {
|
|
102
|
+
categories[cat] = {
|
|
103
|
+
label: CATEGORY_LABELS[cat] || cat,
|
|
104
|
+
repos: [],
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
categories[cat].repos.push(repo.name);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Fetch commits in batches of 5 to avoid secondary rate limits
|
|
111
|
+
const allCommits = [];
|
|
112
|
+
for (const batch of chunks(indiekitRepos, 5)) {
|
|
113
|
+
const results = await Promise.all(
|
|
114
|
+
batch.map(async (repo) => {
|
|
115
|
+
try {
|
|
116
|
+
const commits = await client.getRepoCommits(
|
|
117
|
+
repo.owner.login,
|
|
118
|
+
repo.name,
|
|
119
|
+
20,
|
|
120
|
+
sinceDate,
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
if (!Array.isArray(commits)) return [];
|
|
124
|
+
|
|
125
|
+
// Filter out merge commits and map to response shape
|
|
126
|
+
return commits
|
|
127
|
+
.filter((c) => (c.parents?.length || 0) <= 1)
|
|
128
|
+
.map((c) => ({
|
|
129
|
+
sha: c.sha.slice(0, 7),
|
|
130
|
+
fullSha: c.sha,
|
|
131
|
+
title: c.commit.message.split("\n")[0],
|
|
132
|
+
body: c.commit.message.split("\n").slice(1).join("\n").trim(),
|
|
133
|
+
url: c.html_url,
|
|
134
|
+
date:
|
|
135
|
+
c.commit.author?.date || c.commit.committer?.date || null,
|
|
136
|
+
author: c.commit.author?.name || "Unknown",
|
|
137
|
+
repo: repo.full_name,
|
|
138
|
+
repoName: repo.name,
|
|
139
|
+
repoUrl: repo.html_url,
|
|
140
|
+
category: categorizeRepo(repo.name),
|
|
141
|
+
}));
|
|
142
|
+
} catch {
|
|
143
|
+
return [];
|
|
144
|
+
}
|
|
145
|
+
}),
|
|
146
|
+
);
|
|
147
|
+
allCommits.push(...results.flat());
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Sort by date descending
|
|
151
|
+
allCommits.sort(
|
|
152
|
+
(a, b) => new Date(b.date || 0) - new Date(a.date || 0),
|
|
153
|
+
);
|
|
154
|
+
|
|
155
|
+
response.json({
|
|
156
|
+
commits: allCommits,
|
|
157
|
+
categories,
|
|
158
|
+
totalCommits: allCommits.length,
|
|
159
|
+
days: daysValue,
|
|
160
|
+
generatedAt: new Date().toISOString(),
|
|
161
|
+
});
|
|
162
|
+
} catch (error) {
|
|
163
|
+
next(error);
|
|
164
|
+
}
|
|
165
|
+
},
|
|
166
|
+
};
|
|
@@ -43,7 +43,7 @@ async function fetchCommitsFromRepos(client, username, limit = 10) {
|
|
|
43
43
|
.toSorted((a, b) => new Date(b.date) - new Date(a.date))
|
|
44
44
|
.slice(0, limit);
|
|
45
45
|
} catch (error) {
|
|
46
|
-
console.error("[
|
|
46
|
+
console.error("[GitHub] Error fetching commits from repos:", error.message);
|
|
47
47
|
return [];
|
|
48
48
|
}
|
|
49
49
|
}
|
|
@@ -89,7 +89,7 @@ async function fetchContributionsFromSearch(client, username, limit = 10) {
|
|
|
89
89
|
.toSorted((a, b) => new Date(b.date) - new Date(a.date))
|
|
90
90
|
.slice(0, limit);
|
|
91
91
|
} catch (error) {
|
|
92
|
-
console.error("[
|
|
92
|
+
console.error("[GitHub] Error fetching contributions:", error.message);
|
|
93
93
|
return [];
|
|
94
94
|
}
|
|
95
95
|
}
|
|
@@ -101,12 +101,9 @@ async function fetchContributionsFromSearch(client, username, limit = 10) {
|
|
|
101
101
|
export const dashboardController = {
|
|
102
102
|
async get(request, response, next) {
|
|
103
103
|
try {
|
|
104
|
-
console.log("[GitHub Endpoint] Dashboard controller started");
|
|
105
|
-
|
|
106
104
|
const { githubConfig } = request.app.locals.application;
|
|
107
105
|
|
|
108
106
|
if (!githubConfig) {
|
|
109
|
-
console.error("[GitHub Endpoint] ERROR: githubConfig is undefined");
|
|
110
107
|
return response.status(500).render("github", {
|
|
111
108
|
title: "GitHub",
|
|
112
109
|
actions: [],
|
|
@@ -115,16 +112,8 @@ export const dashboardController = {
|
|
|
115
112
|
}
|
|
116
113
|
|
|
117
114
|
const { username, token, cacheTtl, limits, featuredRepos } = githubConfig;
|
|
118
|
-
console.log("[GitHub Endpoint] Config:", {
|
|
119
|
-
username,
|
|
120
|
-
hasToken: !!token,
|
|
121
|
-
cacheTtl,
|
|
122
|
-
limits,
|
|
123
|
-
featuredRepos: featuredRepos || [],
|
|
124
|
-
});
|
|
125
115
|
|
|
126
116
|
if (!username) {
|
|
127
|
-
console.log("[GitHub Endpoint] No username configured");
|
|
128
117
|
return response.render("github", {
|
|
129
118
|
title: response.locals.__("github.title"),
|
|
130
119
|
actions: [],
|
|
@@ -133,7 +122,6 @@ export const dashboardController = {
|
|
|
133
122
|
}
|
|
134
123
|
|
|
135
124
|
const client = new GitHubClient({ token, cacheTtl });
|
|
136
|
-
console.log("[GitHub Endpoint] Using authenticated API:", !!token);
|
|
137
125
|
|
|
138
126
|
let user;
|
|
139
127
|
let events = [];
|
|
@@ -141,20 +129,14 @@ export const dashboardController = {
|
|
|
141
129
|
let repos = [];
|
|
142
130
|
|
|
143
131
|
try {
|
|
144
|
-
console.log("[GitHub Endpoint] Fetching GitHub data for:", username);
|
|
145
132
|
[user, events, starred, repos] = await Promise.all([
|
|
146
133
|
client.getUser(username),
|
|
147
134
|
client.getUserEvents(username, 30),
|
|
148
135
|
client.getUserStarred(username, limits.stars),
|
|
149
136
|
client.getUserRepos(username, limits.repos || 10),
|
|
150
137
|
]);
|
|
151
|
-
console.log("[GitHub Endpoint] Raw user data:", JSON.stringify(user));
|
|
152
|
-
console.log("[GitHub Endpoint] Events count:", events?.length);
|
|
153
|
-
console.log("[GitHub Endpoint] Event types:", events?.map(e => e.type));
|
|
154
|
-
console.log("[GitHub Endpoint] Starred count:", starred?.length);
|
|
155
|
-
console.log("[GitHub Endpoint] Repos count:", repos?.length);
|
|
156
138
|
} catch (apiError) {
|
|
157
|
-
console.error("[GitHub
|
|
139
|
+
console.error("[GitHub] API error:", apiError.message);
|
|
158
140
|
return response.render("github", {
|
|
159
141
|
title: response.locals.__("github.title"),
|
|
160
142
|
actions: [],
|
|
@@ -162,37 +144,26 @@ export const dashboardController = {
|
|
|
162
144
|
});
|
|
163
145
|
}
|
|
164
146
|
|
|
165
|
-
console.log("[GitHub Endpoint] Processing data...");
|
|
166
147
|
let commits = utils.extractCommits(events);
|
|
167
|
-
console.log("[GitHub Endpoint] Extracted commits from events:", commits?.length);
|
|
168
148
|
|
|
169
149
|
// Fallback: fetch commits directly from repos if events didn't have them
|
|
170
150
|
if (commits.length === 0) {
|
|
171
|
-
console.log("[GitHub Endpoint] Events API returned no commits, fetching from repos");
|
|
172
151
|
commits = await fetchCommitsFromRepos(client, username, limits.commits || 10);
|
|
173
|
-
console.log("[GitHub Endpoint] Fetched commits from repos:", commits?.length);
|
|
174
152
|
}
|
|
175
153
|
|
|
176
154
|
let contributions = utils.extractContributions(events);
|
|
177
|
-
console.log("[GitHub Endpoint] Extracted contributions from events:", contributions?.length);
|
|
178
155
|
|
|
179
156
|
// Fallback: use Search API if events didn't have contributions
|
|
180
157
|
if (contributions.length === 0) {
|
|
181
|
-
console.log("[GitHub Endpoint] Events API returned no contributions, using Search API");
|
|
182
158
|
contributions = await fetchContributionsFromSearch(client, username, limits.contributions || 10);
|
|
183
|
-
console.log("[GitHub Endpoint] Fetched contributions from search:", contributions?.length);
|
|
184
159
|
}
|
|
185
160
|
|
|
186
161
|
const stars = utils.formatStarred(starred);
|
|
187
|
-
console.log("[GitHub Endpoint] Formatted stars:", stars?.length);
|
|
188
|
-
|
|
189
162
|
const repositories = utils.formatRepos(repos);
|
|
190
|
-
console.log("[GitHub Endpoint] Formatted repos:", repositories?.length);
|
|
191
163
|
|
|
192
164
|
// Fetch commits from featured repos
|
|
193
165
|
let featured = [];
|
|
194
166
|
if (featuredRepos && featuredRepos.length > 0) {
|
|
195
|
-
console.log("[GitHub Endpoint] Fetching featured repos:", featuredRepos);
|
|
196
167
|
const featuredPromises = featuredRepos.map(async (repoPath) => {
|
|
197
168
|
const [owner, repo] = repoPath.split("/");
|
|
198
169
|
try {
|
|
@@ -211,34 +182,26 @@ export const dashboardController = {
|
|
|
211
182
|
})),
|
|
212
183
|
};
|
|
213
184
|
} catch (error) {
|
|
214
|
-
console.error(`[GitHub
|
|
185
|
+
console.error(`[GitHub] Error fetching ${repoPath}:`, error.message);
|
|
215
186
|
return null;
|
|
216
187
|
}
|
|
217
188
|
});
|
|
218
189
|
featured = (await Promise.all(featuredPromises)).filter(Boolean);
|
|
219
|
-
console.log("[GitHub Endpoint] Featured repos loaded:", featured.length);
|
|
220
190
|
}
|
|
221
191
|
|
|
222
|
-
const starsLimit = limits.stars || 20;
|
|
223
|
-
const reposLimit = limits.repos || 10;
|
|
224
|
-
|
|
225
|
-
console.log("[GitHub Endpoint] Rendering with limits - stars:", starsLimit, "repos:", reposLimit);
|
|
226
|
-
|
|
227
192
|
response.render("github", {
|
|
228
193
|
title: response.locals.__("github.title"),
|
|
229
194
|
actions: [],
|
|
230
195
|
user,
|
|
231
196
|
commits: commits.slice(0, limits.commits || 10),
|
|
232
197
|
contributions: contributions.slice(0, limits.contributions || 5),
|
|
233
|
-
stars: stars.slice(0,
|
|
234
|
-
repositories: repositories.slice(0,
|
|
198
|
+
stars: stars.slice(0, limits.stars || 20),
|
|
199
|
+
repositories: repositories.slice(0, limits.repos || 10),
|
|
235
200
|
featured,
|
|
236
201
|
mountPath: request.baseUrl,
|
|
237
202
|
});
|
|
238
|
-
console.log("[GitHub Endpoint] Render complete");
|
|
239
203
|
} catch (error) {
|
|
240
|
-
console.error("[GitHub
|
|
241
|
-
console.error("[GitHub Endpoint] Stack:", error.stack);
|
|
204
|
+
console.error("[GitHub] Unexpected error:", error);
|
|
242
205
|
next(error);
|
|
243
206
|
}
|
|
244
207
|
},
|
package/lib/github-client.js
CHANGED
|
@@ -71,10 +71,15 @@ export class GitHubClient {
|
|
|
71
71
|
* @param {string} owner - Repository owner
|
|
72
72
|
* @param {string} repo - Repository name
|
|
73
73
|
* @param {number} [limit] - Number of commits to fetch
|
|
74
|
+
* @param {string} [since] - ISO 8601 date string to filter commits after
|
|
74
75
|
* @returns {Promise<Array>} - Repository commits
|
|
75
76
|
*/
|
|
76
|
-
async getRepoCommits(owner, repo, limit = 10) {
|
|
77
|
-
|
|
77
|
+
async getRepoCommits(owner, repo, limit = 10, since = null) {
|
|
78
|
+
let endpoint = `/repos/${owner}/${repo}/commits?per_page=${limit}`;
|
|
79
|
+
if (since) {
|
|
80
|
+
endpoint += `&since=${since}`;
|
|
81
|
+
}
|
|
82
|
+
return this.fetch(endpoint);
|
|
78
83
|
}
|
|
79
84
|
|
|
80
85
|
/**
|
package/package.json
CHANGED
package/views/activity.njk
CHANGED
package/views/commits.njk
CHANGED
package/views/contributions.njk
CHANGED
package/views/github.njk
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
{% extends "
|
|
1
|
+
{% extends "layouts/github.njk" %}
|
|
2
2
|
|
|
3
|
-
{% block
|
|
3
|
+
{% block github %}
|
|
4
4
|
{% if error %}
|
|
5
5
|
{{ prose({ text: error.message }) }}
|
|
6
6
|
{% else %}
|
|
7
7
|
{# Featured Projects #}
|
|
8
8
|
{% if featured and featured.length > 0 %}
|
|
9
|
-
|
|
10
|
-
<h2>{{ __("github.featured.title") }}</h2>
|
|
9
|
+
{% call section({ title: __("github.featured.title") }) %}
|
|
11
10
|
<div class="github-featured">
|
|
12
11
|
{% for repo in featured %}
|
|
13
12
|
<article class="github-featured__repo">
|
|
@@ -30,8 +29,7 @@
|
|
|
30
29
|
{% endif %}
|
|
31
30
|
</div>
|
|
32
31
|
{% if repo.commits and repo.commits.length > 0 %}
|
|
33
|
-
|
|
34
|
-
<summary>Recent commits ({{ repo.commits.length }})</summary>
|
|
32
|
+
{% call details({ summary: "Recent commits (" ~ repo.commits.length ~ ")" }) %}
|
|
35
33
|
<ul class="github-commit-list">
|
|
36
34
|
{% for commit in repo.commits %}
|
|
37
35
|
<li>
|
|
@@ -41,17 +39,16 @@
|
|
|
41
39
|
</li>
|
|
42
40
|
{% endfor %}
|
|
43
41
|
</ul>
|
|
44
|
-
|
|
42
|
+
{% endcall %}
|
|
45
43
|
{% endif %}
|
|
46
44
|
</article>
|
|
47
45
|
{% endfor %}
|
|
48
46
|
</div>
|
|
49
|
-
|
|
47
|
+
{% endcall %}
|
|
50
48
|
{% endif %}
|
|
51
49
|
|
|
52
50
|
{# Recent Commits #}
|
|
53
|
-
|
|
54
|
-
<h2>{{ __("github.commits.title") }}</h2>
|
|
51
|
+
{% call section({ title: __("github.commits.title") }) %}
|
|
55
52
|
{% if commits and commits.length > 0 %}
|
|
56
53
|
<ul class="github-list">
|
|
57
54
|
{% for commit in commits %}
|
|
@@ -67,11 +64,10 @@
|
|
|
67
64
|
{% else %}
|
|
68
65
|
{{ prose({ text: __("github.commits.none") }) }}
|
|
69
66
|
{% endif %}
|
|
70
|
-
|
|
67
|
+
{% endcall %}
|
|
71
68
|
|
|
72
69
|
{# Recently Starred #}
|
|
73
|
-
|
|
74
|
-
<h2>{{ __("github.stars.title") }}</h2>
|
|
70
|
+
{% call section({ title: __("github.stars.title") }) %}
|
|
75
71
|
{% if stars and stars.length > 0 %}
|
|
76
72
|
<ul class="github-list github-list--grid">
|
|
77
73
|
{% for star in stars %}
|
|
@@ -92,12 +88,11 @@
|
|
|
92
88
|
{% else %}
|
|
93
89
|
{{ prose({ text: __("github.stars.none") }) }}
|
|
94
90
|
{% endif %}
|
|
95
|
-
|
|
91
|
+
{% endcall %}
|
|
96
92
|
|
|
97
93
|
{# PRs & Issues #}
|
|
98
94
|
{% if contributions and contributions.length > 0 %}
|
|
99
|
-
|
|
100
|
-
<h2>{{ __("github.contributions.title") }}</h2>
|
|
95
|
+
{% call section({ title: __("github.contributions.title") }) %}
|
|
101
96
|
<ul class="github-list">
|
|
102
97
|
{% for item in contributions %}
|
|
103
98
|
<li class="github-list__item">
|
|
@@ -113,12 +108,11 @@
|
|
|
113
108
|
</li>
|
|
114
109
|
{% endfor %}
|
|
115
110
|
</ul>
|
|
116
|
-
|
|
111
|
+
{% endcall %}
|
|
117
112
|
{% endif %}
|
|
118
113
|
|
|
119
114
|
{# My Repositories #}
|
|
120
|
-
|
|
121
|
-
<h2>{{ __("github.repos.title") }}</h2>
|
|
115
|
+
{% call section({ title: __("github.repos.title") }) %}
|
|
122
116
|
{% if repositories and repositories.length > 0 %}
|
|
123
117
|
<ul class="github-list github-list--grid">
|
|
124
118
|
{% for repo in repositories %}
|
|
@@ -150,6 +144,6 @@
|
|
|
150
144
|
{% else %}
|
|
151
145
|
{{ prose({ text: __("github.repos.none") }) }}
|
|
152
146
|
{% endif %}
|
|
153
|
-
|
|
147
|
+
{% endcall %}
|
|
154
148
|
{% endif %}
|
|
155
149
|
{% endblock %}
|
package/views/stars.njk
CHANGED