@larkiny/astro-github-loader 0.11.2 โ 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 +69 -61
- 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 +6 -132
- package/dist/github.content.js +154 -789
- 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 +45 -51
- 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 +41 -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 +261 -950
- 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 +113 -78
- 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 +55 -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,13 +45,13 @@ export function githubLoader({
|
|
|
67
45
|
return {
|
|
68
46
|
name: "github-loader",
|
|
69
47
|
load: async (context) => {
|
|
70
|
-
const { store } = context;
|
|
71
|
-
|
|
72
48
|
// Create global logger with specified level or default
|
|
73
|
-
const globalLogger = createLogger(logLevel ||
|
|
49
|
+
const globalLogger = createLogger(logLevel || "default");
|
|
74
50
|
|
|
75
51
|
if (dryRun) {
|
|
76
|
-
globalLogger.info(
|
|
52
|
+
globalLogger.info(
|
|
53
|
+
"๐ Dry run mode enabled - checking for changes only",
|
|
54
|
+
);
|
|
77
55
|
|
|
78
56
|
try {
|
|
79
57
|
const results = await performDryRun(configs, context, octokit);
|
|
@@ -83,40 +61,48 @@ export function githubLoader({
|
|
|
83
61
|
globalLogger.info("๐ก Set dryRun: false to perform actual imports");
|
|
84
62
|
|
|
85
63
|
return; // Exit without importing
|
|
86
|
-
} catch (error:
|
|
87
|
-
globalLogger.error(
|
|
64
|
+
} catch (error: unknown) {
|
|
65
|
+
globalLogger.error(
|
|
66
|
+
`Dry run failed: ${error instanceof Error ? error.message : String(error)}`,
|
|
67
|
+
);
|
|
88
68
|
throw error;
|
|
89
69
|
}
|
|
90
70
|
}
|
|
91
71
|
|
|
92
72
|
globalLogger.debug(`Loading data from ${configs.length} sources`);
|
|
93
73
|
|
|
94
|
-
//
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
74
|
+
// Log clear mode status - actual clearing happens per-entry in toCollectionEntry
|
|
75
|
+
// to avoid breaking Astro's content collection by emptying the store all at once
|
|
76
|
+
globalLogger.info(
|
|
77
|
+
clear
|
|
78
|
+
? "Processing with selective entry replacement"
|
|
79
|
+
: "Processing without entry replacement",
|
|
80
|
+
);
|
|
100
81
|
|
|
101
82
|
// Process each config sequentially to avoid overwhelming GitHub API/CDN
|
|
102
83
|
for (let i = 0; i < configs.length; i++) {
|
|
103
84
|
const config = configs[i];
|
|
104
85
|
|
|
105
86
|
if (config.enabled === false) {
|
|
106
|
-
globalLogger.debug(
|
|
87
|
+
globalLogger.debug(
|
|
88
|
+
`Skipping disabled config: ${config.name || `${config.owner}/${config.repo}`}`,
|
|
89
|
+
);
|
|
107
90
|
continue;
|
|
108
91
|
}
|
|
109
92
|
|
|
110
93
|
// Add small delay between configs to be gentler on GitHub's CDN
|
|
111
94
|
if (i > 0) {
|
|
112
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
95
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
113
96
|
}
|
|
114
97
|
|
|
115
98
|
// Determine the effective log level for this config
|
|
116
|
-
const effectiveLogLevel = logLevel || config.logLevel ||
|
|
99
|
+
const effectiveLogLevel = logLevel || config.logLevel || "default";
|
|
117
100
|
const configLogger = createLogger(effectiveLogLevel);
|
|
118
101
|
|
|
119
|
-
const
|
|
102
|
+
const langSuffix = config.language ? ` (${config.language})` : "";
|
|
103
|
+
const configName = config.name
|
|
104
|
+
? `${config.name}${langSuffix}`
|
|
105
|
+
: `${config.owner}/${config.repo}${langSuffix}`;
|
|
120
106
|
const repository = `${config.owner}/${config.repo}`;
|
|
121
107
|
|
|
122
108
|
let summary: ImportSummary = {
|
|
@@ -127,7 +113,7 @@ export function githubLoader({
|
|
|
127
113
|
filesUpdated: 0,
|
|
128
114
|
filesUnchanged: 0,
|
|
129
115
|
duration: 0,
|
|
130
|
-
status:
|
|
116
|
+
status: "error",
|
|
131
117
|
};
|
|
132
118
|
|
|
133
119
|
const startTime = Date.now();
|
|
@@ -138,51 +124,92 @@ export function githubLoader({
|
|
|
138
124
|
|
|
139
125
|
if (!force) {
|
|
140
126
|
try {
|
|
141
|
-
const state = await loadImportState(process.cwd());
|
|
127
|
+
const state = await loadImportState(process.cwd(), configLogger);
|
|
142
128
|
const currentState = state.imports[configId];
|
|
143
129
|
|
|
144
130
|
if (currentState && currentState.lastCommitSha) {
|
|
145
|
-
configLogger.debug(
|
|
131
|
+
configLogger.debug(
|
|
132
|
+
`๐ Checking repository changes for ${configName}...`,
|
|
133
|
+
);
|
|
146
134
|
const latestCommit = await getLatestCommitInfo(octokit, config);
|
|
147
135
|
|
|
148
|
-
if (
|
|
149
|
-
|
|
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
|
+
);
|
|
150
143
|
|
|
151
144
|
// Update summary for unchanged repository
|
|
152
145
|
summary.duration = Date.now() - startTime;
|
|
153
146
|
summary.filesProcessed = 0;
|
|
154
147
|
summary.filesUpdated = 0;
|
|
155
148
|
summary.filesUnchanged = 0;
|
|
156
|
-
summary.status =
|
|
149
|
+
summary.status = "success";
|
|
157
150
|
|
|
158
151
|
configLogger.logImportSummary(summary);
|
|
159
152
|
continue; // Skip to next config
|
|
160
153
|
} else if (latestCommit) {
|
|
161
|
-
configLogger.info(
|
|
154
|
+
configLogger.info(
|
|
155
|
+
`๐ Repository ${configName} changed (${currentState.lastCommitSha?.slice(0, 7) || "unknown"} -> ${latestCommit.sha.slice(0, 7)}) - proceeding with import`,
|
|
156
|
+
);
|
|
162
157
|
}
|
|
163
158
|
} else {
|
|
164
|
-
configLogger.debug(
|
|
159
|
+
configLogger.debug(
|
|
160
|
+
`๐ฅ First time importing ${configName} - no previous state found`,
|
|
161
|
+
);
|
|
165
162
|
}
|
|
166
163
|
} catch (error) {
|
|
167
|
-
configLogger.warn(
|
|
164
|
+
configLogger.warn(
|
|
165
|
+
`Failed to check repository state for ${configName}: ${error instanceof Error ? error.message : String(error)}`,
|
|
166
|
+
);
|
|
168
167
|
// Continue with import if state check fails
|
|
169
168
|
}
|
|
170
169
|
} else {
|
|
171
|
-
configLogger.info(
|
|
170
|
+
configLogger.info(
|
|
171
|
+
`๐ Force mode enabled for ${configName} - proceeding with full import`,
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Determine effective clear setting: per-config takes precedence over global
|
|
176
|
+
const effectiveClear = config.clear ?? clear;
|
|
177
|
+
|
|
178
|
+
// Perform selective cleanup before importing if clear is enabled
|
|
179
|
+
if (effectiveClear) {
|
|
180
|
+
configLogger.info(
|
|
181
|
+
`๐งน Clearing obsolete files for ${configName}...`,
|
|
182
|
+
);
|
|
183
|
+
try {
|
|
184
|
+
await performSelectiveCleanup(
|
|
185
|
+
config,
|
|
186
|
+
{ ...context, logger: configLogger } as ExtendedLoaderContext,
|
|
187
|
+
octokit,
|
|
188
|
+
);
|
|
189
|
+
} catch (error) {
|
|
190
|
+
configLogger.warn(
|
|
191
|
+
`Cleanup failed for ${configName}, continuing with import: ${error}`,
|
|
192
|
+
);
|
|
193
|
+
}
|
|
172
194
|
}
|
|
173
195
|
|
|
174
196
|
// Perform the import with spinner
|
|
175
197
|
const stats = await globalLogger.withSpinner(
|
|
176
198
|
`๐ Importing ${configName}...`,
|
|
177
|
-
() =>
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
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
|
+
}),
|
|
184
211
|
`โ
${configName} imported successfully`,
|
|
185
|
-
`โ ${configName} import failed
|
|
212
|
+
`โ ${configName} import failed`,
|
|
186
213
|
);
|
|
187
214
|
|
|
188
215
|
summary.duration = Date.now() - startTime;
|
|
@@ -191,7 +218,7 @@ export function githubLoader({
|
|
|
191
218
|
summary.filesUnchanged = stats?.unchanged || 0;
|
|
192
219
|
summary.assetsDownloaded = stats?.assetsDownloaded || 0;
|
|
193
220
|
summary.assetsCached = stats?.assetsCached || 0;
|
|
194
|
-
summary.status =
|
|
221
|
+
summary.status = "success";
|
|
195
222
|
|
|
196
223
|
// Log structured summary
|
|
197
224
|
configLogger.logImportSummary(summary);
|
|
@@ -202,21 +229,29 @@ export function githubLoader({
|
|
|
202
229
|
const { data } = await octokit.rest.repos.listCommits({
|
|
203
230
|
owner: config.owner,
|
|
204
231
|
repo: config.repo,
|
|
205
|
-
sha: config.ref ||
|
|
206
|
-
per_page: 1
|
|
232
|
+
sha: config.ref || "main",
|
|
233
|
+
per_page: 1,
|
|
207
234
|
});
|
|
208
235
|
|
|
209
236
|
if (data.length > 0) {
|
|
210
|
-
await updateImportState(
|
|
237
|
+
await updateImportState(
|
|
238
|
+
process.cwd(),
|
|
239
|
+
config,
|
|
240
|
+
data[0].sha,
|
|
241
|
+
configLogger,
|
|
242
|
+
);
|
|
211
243
|
}
|
|
212
244
|
} catch (error) {
|
|
213
245
|
// Don't fail the import if state tracking fails
|
|
214
|
-
configLogger.debug(
|
|
246
|
+
configLogger.debug(
|
|
247
|
+
`Failed to update import state for ${configName}: ${error}`,
|
|
248
|
+
);
|
|
215
249
|
}
|
|
216
|
-
} catch (error:
|
|
250
|
+
} catch (error: unknown) {
|
|
217
251
|
summary.duration = Date.now() - startTime;
|
|
218
|
-
summary.status =
|
|
219
|
-
summary.error =
|
|
252
|
+
summary.status = "error";
|
|
253
|
+
summary.error =
|
|
254
|
+
error instanceof Error ? error.message : String(error);
|
|
220
255
|
|
|
221
256
|
configLogger.logImportSummary(summary);
|
|
222
257
|
// Continue with other configs even if one fails
|