@larkiny/astro-github-loader 0.11.3 โ 0.12.0
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/README.md +28 -55
- package/dist/github.assets.d.ts +70 -0
- package/dist/github.assets.js +253 -0
- package/dist/github.auth.js +13 -9
- package/dist/github.cleanup.d.ts +3 -2
- package/dist/github.cleanup.js +30 -23
- package/dist/github.constants.d.ts +0 -16
- package/dist/github.constants.js +0 -16
- package/dist/github.content.d.ts +5 -131
- package/dist/github.content.js +152 -794
- package/dist/github.dryrun.d.ts +9 -5
- package/dist/github.dryrun.js +46 -25
- package/dist/github.link-transform.d.ts +2 -2
- package/dist/github.link-transform.js +65 -57
- package/dist/github.loader.js +30 -46
- package/dist/github.logger.d.ts +2 -2
- package/dist/github.logger.js +33 -24
- package/dist/github.paths.d.ts +76 -0
- package/dist/github.paths.js +190 -0
- package/dist/github.storage.d.ts +15 -0
- package/dist/github.storage.js +109 -0
- package/dist/github.types.d.ts +34 -4
- package/dist/index.d.ts +8 -6
- package/dist/index.js +3 -6
- package/dist/test-helpers.d.ts +130 -0
- package/dist/test-helpers.js +194 -0
- package/package.json +3 -1
- package/src/github.assets.spec.ts +717 -0
- package/src/github.assets.ts +365 -0
- package/src/github.auth.spec.ts +245 -0
- package/src/github.auth.ts +24 -10
- package/src/github.cleanup.spec.ts +380 -0
- package/src/github.cleanup.ts +91 -47
- package/src/github.constants.ts +0 -17
- package/src/github.content.spec.ts +305 -454
- package/src/github.content.ts +259 -957
- package/src/github.dryrun.spec.ts +586 -0
- package/src/github.dryrun.ts +105 -54
- package/src/github.link-transform.spec.ts +1345 -0
- package/src/github.link-transform.ts +174 -95
- package/src/github.loader.spec.ts +75 -50
- package/src/github.loader.ts +101 -76
- package/src/github.logger.spec.ts +795 -0
- package/src/github.logger.ts +77 -35
- package/src/github.paths.spec.ts +523 -0
- package/src/github.paths.ts +259 -0
- package/src/github.storage.spec.ts +367 -0
- package/src/github.storage.ts +127 -0
- package/src/github.types.ts +48 -9
- package/src/index.ts +43 -6
- package/src/test-helpers.ts +215 -0
package/src/github.loader.ts
CHANGED
|
@@ -1,48 +1,26 @@
|
|
|
1
1
|
import { toCollectionEntry } from "./github.content.js";
|
|
2
2
|
import { performSelectiveCleanup } from "./github.cleanup.js";
|
|
3
|
-
import {
|
|
4
|
-
|
|
3
|
+
import {
|
|
4
|
+
performDryRun,
|
|
5
|
+
displayDryRunResults,
|
|
6
|
+
updateImportState,
|
|
7
|
+
loadImportState,
|
|
8
|
+
createConfigId,
|
|
9
|
+
getLatestCommitInfo,
|
|
10
|
+
} from "./github.dryrun.js";
|
|
11
|
+
import {
|
|
12
|
+
createLogger,
|
|
13
|
+
type Logger,
|
|
14
|
+
type ImportSummary,
|
|
15
|
+
} from "./github.logger.js";
|
|
5
16
|
|
|
6
17
|
import type {
|
|
7
18
|
Loader,
|
|
8
19
|
GithubLoaderOptions,
|
|
20
|
+
ExtendedLoaderContext,
|
|
9
21
|
ImportOptions,
|
|
10
|
-
SyncStats,
|
|
11
22
|
} from "./github.types.js";
|
|
12
23
|
|
|
13
|
-
/**
|
|
14
|
-
* Performs selective cleanup for configurations with basePath
|
|
15
|
-
* @param configs - Array of configuration objects
|
|
16
|
-
* @param context - Loader context
|
|
17
|
-
* @param octokit - GitHub API client
|
|
18
|
-
* @internal
|
|
19
|
-
*/
|
|
20
|
-
async function performSelectiveCleanups(
|
|
21
|
-
configs: ImportOptions[],
|
|
22
|
-
context: any,
|
|
23
|
-
octokit: any
|
|
24
|
-
): Promise<SyncStats[]> {
|
|
25
|
-
const results: SyncStats[] = [];
|
|
26
|
-
|
|
27
|
-
// Process each config sequentially to avoid overwhelming Astro's file watcher
|
|
28
|
-
for (const config of configs) {
|
|
29
|
-
if (config.enabled === false) {
|
|
30
|
-
context.logger.debug(`Skipping disabled config: ${config.name || `${config.owner}/${config.repo}`}`);
|
|
31
|
-
continue;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
try {
|
|
35
|
-
const stats = await performSelectiveCleanup(config, context, octokit);
|
|
36
|
-
results.push(stats);
|
|
37
|
-
} catch (error: any) {
|
|
38
|
-
context.logger.error(`Selective cleanup failed for ${config.name || `${config.owner}/${config.repo}`}: ${error}`);
|
|
39
|
-
// Continue with other configs even if one fails
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
return results;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
24
|
/**
|
|
47
25
|
* Loads data from GitHub repositories based on the provided configurations and options.
|
|
48
26
|
*
|
|
@@ -67,12 +45,13 @@ export function githubLoader({
|
|
|
67
45
|
return {
|
|
68
46
|
name: "github-loader",
|
|
69
47
|
load: async (context) => {
|
|
70
|
-
|
|
71
48
|
// Create global logger with specified level or default
|
|
72
|
-
const globalLogger = createLogger(logLevel ||
|
|
49
|
+
const globalLogger = createLogger(logLevel || "default");
|
|
73
50
|
|
|
74
51
|
if (dryRun) {
|
|
75
|
-
globalLogger.info(
|
|
52
|
+
globalLogger.info(
|
|
53
|
+
"๐ Dry run mode enabled - checking for changes only",
|
|
54
|
+
);
|
|
76
55
|
|
|
77
56
|
try {
|
|
78
57
|
const results = await performDryRun(configs, context, octokit);
|
|
@@ -82,8 +61,10 @@ export function githubLoader({
|
|
|
82
61
|
globalLogger.info("๐ก Set dryRun: false to perform actual imports");
|
|
83
62
|
|
|
84
63
|
return; // Exit without importing
|
|
85
|
-
} catch (error:
|
|
86
|
-
globalLogger.error(
|
|
64
|
+
} catch (error: unknown) {
|
|
65
|
+
globalLogger.error(
|
|
66
|
+
`Dry run failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
67
|
+
);
|
|
87
68
|
throw error;
|
|
88
69
|
}
|
|
89
70
|
}
|
|
@@ -92,27 +73,36 @@ export function githubLoader({
|
|
|
92
73
|
|
|
93
74
|
// Log clear mode status - actual clearing happens per-entry in toCollectionEntry
|
|
94
75
|
// to avoid breaking Astro's content collection by emptying the store all at once
|
|
95
|
-
globalLogger.info(
|
|
76
|
+
globalLogger.info(
|
|
77
|
+
clear
|
|
78
|
+
? "Processing with selective entry replacement"
|
|
79
|
+
: "Processing without entry replacement",
|
|
80
|
+
);
|
|
96
81
|
|
|
97
82
|
// Process each config sequentially to avoid overwhelming GitHub API/CDN
|
|
98
83
|
for (let i = 0; i < configs.length; i++) {
|
|
99
84
|
const config = configs[i];
|
|
100
85
|
|
|
101
86
|
if (config.enabled === false) {
|
|
102
|
-
globalLogger.debug(
|
|
87
|
+
globalLogger.debug(
|
|
88
|
+
`Skipping disabled config: ${config.name || `${config.owner}/${config.repo}`}`,
|
|
89
|
+
);
|
|
103
90
|
continue;
|
|
104
91
|
}
|
|
105
92
|
|
|
106
93
|
// Add small delay between configs to be gentler on GitHub's CDN
|
|
107
94
|
if (i > 0) {
|
|
108
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
95
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
109
96
|
}
|
|
110
97
|
|
|
111
98
|
// Determine the effective log level for this config
|
|
112
|
-
const effectiveLogLevel = logLevel || config.logLevel ||
|
|
99
|
+
const effectiveLogLevel = logLevel || config.logLevel || "default";
|
|
113
100
|
const configLogger = createLogger(effectiveLogLevel);
|
|
114
101
|
|
|
115
|
-
const
|
|
102
|
+
const langSuffix = config.language ? ` (${config.language})` : "";
|
|
103
|
+
const configName = config.name
|
|
104
|
+
? `${config.name}${langSuffix}`
|
|
105
|
+
: `${config.owner}/${config.repo}${langSuffix}`;
|
|
116
106
|
const repository = `${config.owner}/${config.repo}`;
|
|
117
107
|
|
|
118
108
|
let summary: ImportSummary = {
|
|
@@ -123,7 +113,7 @@ export function githubLoader({
|
|
|
123
113
|
filesUpdated: 0,
|
|
124
114
|
filesUnchanged: 0,
|
|
125
115
|
duration: 0,
|
|
126
|
-
status:
|
|
116
|
+
status: "error",
|
|
127
117
|
};
|
|
128
118
|
|
|
129
119
|
const startTime = Date.now();
|
|
@@ -134,37 +124,52 @@ export function githubLoader({
|
|
|
134
124
|
|
|
135
125
|
if (!force) {
|
|
136
126
|
try {
|
|
137
|
-
const state = await loadImportState(process.cwd());
|
|
127
|
+
const state = await loadImportState(process.cwd(), configLogger);
|
|
138
128
|
const currentState = state.imports[configId];
|
|
139
129
|
|
|
140
130
|
if (currentState && currentState.lastCommitSha) {
|
|
141
|
-
configLogger.debug(
|
|
131
|
+
configLogger.debug(
|
|
132
|
+
`๐ Checking repository changes for ${configName}...`,
|
|
133
|
+
);
|
|
142
134
|
const latestCommit = await getLatestCommitInfo(octokit, config);
|
|
143
135
|
|
|
144
|
-
if (
|
|
145
|
-
|
|
136
|
+
if (
|
|
137
|
+
latestCommit &&
|
|
138
|
+
currentState.lastCommitSha === latestCommit.sha
|
|
139
|
+
) {
|
|
140
|
+
configLogger.info(
|
|
141
|
+
`โ
Repository ${configName} unchanged (${latestCommit.sha.slice(0, 7)}) - skipping import`,
|
|
142
|
+
);
|
|
146
143
|
|
|
147
144
|
// Update summary for unchanged repository
|
|
148
145
|
summary.duration = Date.now() - startTime;
|
|
149
146
|
summary.filesProcessed = 0;
|
|
150
147
|
summary.filesUpdated = 0;
|
|
151
148
|
summary.filesUnchanged = 0;
|
|
152
|
-
summary.status =
|
|
149
|
+
summary.status = "success";
|
|
153
150
|
|
|
154
151
|
configLogger.logImportSummary(summary);
|
|
155
152
|
continue; // Skip to next config
|
|
156
153
|
} else if (latestCommit) {
|
|
157
|
-
configLogger.info(
|
|
154
|
+
configLogger.info(
|
|
155
|
+
`๐ Repository ${configName} changed (${currentState.lastCommitSha?.slice(0, 7) || "unknown"} -> ${latestCommit.sha.slice(0, 7)}) - proceeding with import`,
|
|
156
|
+
);
|
|
158
157
|
}
|
|
159
158
|
} else {
|
|
160
|
-
configLogger.debug(
|
|
159
|
+
configLogger.debug(
|
|
160
|
+
`๐ฅ First time importing ${configName} - no previous state found`,
|
|
161
|
+
);
|
|
161
162
|
}
|
|
162
163
|
} catch (error) {
|
|
163
|
-
configLogger.warn(
|
|
164
|
+
configLogger.warn(
|
|
165
|
+
`Failed to check repository state for ${configName}: ${error instanceof Error ? error.message : String(error)}`,
|
|
166
|
+
);
|
|
164
167
|
// Continue with import if state check fails
|
|
165
168
|
}
|
|
166
169
|
} else {
|
|
167
|
-
configLogger.info(
|
|
170
|
+
configLogger.info(
|
|
171
|
+
`๐ Force mode enabled for ${configName} - proceeding with full import`,
|
|
172
|
+
);
|
|
168
173
|
}
|
|
169
174
|
|
|
170
175
|
// Determine effective clear setting: per-config takes precedence over global
|
|
@@ -172,27 +177,39 @@ export function githubLoader({
|
|
|
172
177
|
|
|
173
178
|
// Perform selective cleanup before importing if clear is enabled
|
|
174
179
|
if (effectiveClear) {
|
|
175
|
-
configLogger.info(
|
|
180
|
+
configLogger.info(
|
|
181
|
+
`๐งน Clearing obsolete files for ${configName}...`,
|
|
182
|
+
);
|
|
176
183
|
try {
|
|
177
|
-
await performSelectiveCleanup(
|
|
184
|
+
await performSelectiveCleanup(
|
|
185
|
+
config,
|
|
186
|
+
{ ...context, logger: configLogger } as ExtendedLoaderContext,
|
|
187
|
+
octokit,
|
|
188
|
+
);
|
|
178
189
|
} catch (error) {
|
|
179
|
-
configLogger.warn(
|
|
190
|
+
configLogger.warn(
|
|
191
|
+
`Cleanup failed for ${configName}, continuing with import: ${error}`,
|
|
192
|
+
);
|
|
180
193
|
}
|
|
181
194
|
}
|
|
182
195
|
|
|
183
196
|
// Perform the import with spinner
|
|
184
197
|
const stats = await globalLogger.withSpinner(
|
|
185
198
|
`๐ Importing ${configName}...`,
|
|
186
|
-
() =>
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
199
|
+
() =>
|
|
200
|
+
toCollectionEntry({
|
|
201
|
+
context: {
|
|
202
|
+
...context,
|
|
203
|
+
logger: configLogger,
|
|
204
|
+
} as ExtendedLoaderContext,
|
|
205
|
+
octokit,
|
|
206
|
+
options: config,
|
|
207
|
+
fetchOptions,
|
|
208
|
+
force,
|
|
209
|
+
clear: effectiveClear,
|
|
210
|
+
}),
|
|
194
211
|
`โ
${configName} imported successfully`,
|
|
195
|
-
`โ ${configName} import failed
|
|
212
|
+
`โ ${configName} import failed`,
|
|
196
213
|
);
|
|
197
214
|
|
|
198
215
|
summary.duration = Date.now() - startTime;
|
|
@@ -201,7 +218,7 @@ export function githubLoader({
|
|
|
201
218
|
summary.filesUnchanged = stats?.unchanged || 0;
|
|
202
219
|
summary.assetsDownloaded = stats?.assetsDownloaded || 0;
|
|
203
220
|
summary.assetsCached = stats?.assetsCached || 0;
|
|
204
|
-
summary.status =
|
|
221
|
+
summary.status = "success";
|
|
205
222
|
|
|
206
223
|
// Log structured summary
|
|
207
224
|
configLogger.logImportSummary(summary);
|
|
@@ -212,21 +229,29 @@ export function githubLoader({
|
|
|
212
229
|
const { data } = await octokit.rest.repos.listCommits({
|
|
213
230
|
owner: config.owner,
|
|
214
231
|
repo: config.repo,
|
|
215
|
-
sha: config.ref ||
|
|
216
|
-
per_page: 1
|
|
232
|
+
sha: config.ref || "main",
|
|
233
|
+
per_page: 1,
|
|
217
234
|
});
|
|
218
235
|
|
|
219
236
|
if (data.length > 0) {
|
|
220
|
-
await updateImportState(
|
|
237
|
+
await updateImportState(
|
|
238
|
+
process.cwd(),
|
|
239
|
+
config,
|
|
240
|
+
data[0].sha,
|
|
241
|
+
configLogger,
|
|
242
|
+
);
|
|
221
243
|
}
|
|
222
244
|
} catch (error) {
|
|
223
245
|
// Don't fail the import if state tracking fails
|
|
224
|
-
configLogger.debug(
|
|
246
|
+
configLogger.debug(
|
|
247
|
+
`Failed to update import state for ${configName}: ${error}`,
|
|
248
|
+
);
|
|
225
249
|
}
|
|
226
|
-
} catch (error:
|
|
250
|
+
} catch (error: unknown) {
|
|
227
251
|
summary.duration = Date.now() - startTime;
|
|
228
|
-
summary.status =
|
|
229
|
-
summary.error =
|
|
252
|
+
summary.status = "error";
|
|
253
|
+
summary.error =
|
|
254
|
+
error instanceof Error ? error.message : String(error);
|
|
230
255
|
|
|
231
256
|
configLogger.logImportSummary(summary);
|
|
232
257
|
// Continue with other configs even if one fails
|